Differencebetween Synchronized on Lockobject and Using This as the Lock

What is the difference between synchronized on lockObject and using this as the lock?

Personally I almost never lock on "this". I usually lock on a privately held reference which I know that no other code is going to lock on. If you lock on "this" then any other code which knows about your object might choose to lock on it. While it's unlikely to happen, it certainly could do - and could cause deadlocks, or just excessive locking.

There's nothing particularly magical about what you lock on - you can think of it as a token, effectively. Anyone locking with the same token will be trying to acquire the same lock. Unless you want other code to be able to acquire the same lock, use a private variable. I'd also encourage you to make the variable final - I can't remember a situation where I've ever wanted to change a lock variable over the lifetime of an object.

Java synchronized method lock on object, or method?

If you declare the method as synchronized (as you're doing by typing public synchronized void addA()) you synchronize on the whole object, so two thread accessing a different variable from this same object would block each other anyway.

If you want to synchronize only on one variable at a time, so two threads won't block each other while accessing different variables, you have synchronize on them separately in synchronized () blocks. If a and b were object references you would use:

public void addA() {
synchronized( a ) {
a++;
}
}

public void addB() {
synchronized( b ) {
b++;
}
}

But since they're primitives you can't do this.

I would suggest you to use AtomicInteger instead:

import java.util.concurrent.atomic.AtomicInteger;

class X {

AtomicInteger a;
AtomicInteger b;

public void addA(){
a.incrementAndGet();
}

public void addB(){
b.incrementAndGet();
}
}

Does synchronized (this) lock only the synchronized block or all the this code?

Using synchronized means in order for a thread to execute that block or method, it has to acquire a lock referenced (explicitly or implicitly) by that block or method. For the static synchronized methods, that lock is the monitor on the class object. For the synchronized(this) block, the lock used is the monitor on the current instance. Sharing of locks between multiple methods or blocks is what enforces atomicity and memory visibility of updates, also the shared lock provides a shared communication path through which waiting and notification can take place.

Since the static synchronized blocks use a different lock from that used by the block in the constructor, entering a static synchronized block is not blocked by another thread's accessing the block that requires acquiring the lock on the current instance, and the synchronized block in the constructor has no effect on anything, the lock acquisition will always be uncontended. More importantly here, changes made by one thread in the constructor may not get seen by other threads using the getter. Synchronization affects both locking and memory visibility.

This changed version would work:

public class ObjectCounter {
private static long numOfInstances = 0;
public ObjectCounter(){
synchronized(ObjectCounter.class){
numOfInstances++;
}
}
public static synchronized long getCount(){
return numOfInstances;
}
}

because the getter and the incrementing block are using the same lock. Making the different threads acquire the same monitor ensures that the change to the counter gets safely published so that another thread accessing the getter can see the updated value.

The synchronized keyword says, "you have to acquire a lock before you can enter", where for the method the lock is assumed: with the static keyword on the method it's the monitor on the class, without a static keyword it's the monitor on the current instance. For locking to work correctly the different blocks and methods need to use the same lock. There is arguably too much syntax sugar and too much making things convenient in how Java was designed: allowing implicit choice of locks and putting the monitor on java.lang.Object can cause confusion.

WRT your question #6: For what you're doing here you'd be better off with an AtomicLong. Use synchronized blocks for coordinating multiple changes that need to take place without interference from other threads.

Questions #3, #7 and #8 seem very similar: If a method/block isn't attempting to acquire a lock, nothing prevents threads from executing that method/block. The object as a whole doesn't get any protection, using the synchronized methods or blocks to enforce locking is what does the protecting. Think less in terms of "using the synchronized keyword" and more in terms of what lock threads need to acquire.

Synchronization vs Lock

If you're simply locking an object, I'd prefer to use synchronized

Example:

Lock.acquire();
doSomethingNifty(); // Throws a NPE!
Lock.release(); // Oh noes, we never release the lock!

You have to explicitly do try{} finally{} everywhere.

Whereas with synchronized, it's super clear and impossible to get wrong:

synchronized(myObject) {
doSomethingNifty();
}

That said, Locks may be more useful for more complicated things where you can't acquire and release in such a clean manner. I would honestly prefer to avoid using bare Locks in the first place, and just go with a more sophisticated concurrency control such as a CyclicBarrier or a LinkedBlockingQueue, if they meet your needs.

I've never had a reason to use wait() or notify() but there may be some good ones.

What's the difference between Synchronized and Lock in my example?

First of all, your example using synchronized is ill conceived: it is a very bad idea to synchronize on object "A". Use the following idiom instead:

private final Object lock = new Object();

public void run() {
synchronized (lock) {
doSomething();
}
}

This is better because by hiding your lock from external objects, you are encapsulating your synchronization protocol and thereby implementing a safer synchronization policy.

Now, the difference between synchronized and java.util.concurrent.locks.Lock, is that the former is a synchronization primitive whereas the latter a higher level locking construct which provides more elaborate operations than synchornized.

Fore more information you may look at http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html and http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html in particular.

Why do we need to specify the lock for synchronized statements?

Given that there's only one lock for each instance of a class, then why doesn't Java just allow us to do this:

void method() {
synchronized {
// do something
}

// do other things
}

Although an intrinsic lock is provided with each instance,
that's not necessarily the "obvious" lock to use.

You're perhaps right that they could have provided synchronized { ... } as a shorthand for synchronized (this) { ... }.
I don't know why they didn't, but I never missed it.
But concurrent programming is tricky,
so making the lock object an explicit required parameter may make things clearer to readers, which is a good thing, as @ajb pointed out in a comment.
In any case, I don't think syntax is your main question, so let's move on.

What's the purpose of specifying a lock?

Uhm, the lock is perhaps the single most important thing in the synchronization mechanism. The key point in synchronization is that only one thread can hold the same lock. Two threads holding different locks are not synchronized. So knowing what is the lock guarding the synchronization is crucial.

Does it make a difference if I choose one object as a lock over the other?

I hope the previous section makes it clear that yes, you have to choose the object carefully. It has to be an object visible by all threads involved,
it has to be not null, and it has to be something that won't get reassigned during the period of synchronization.

Or could I just choose any random object?

Certainly not. See the previous section.

To understand concurrency in Java, I recommend the book Java Concurrency in Practice by one of the authors of the API, or Oracle's tutorials on the subject.

Static versus non-static lock object in synchronized block

The difference is simple: if the locked-on object is in a static field, then all instances of MyClass* will share that lock (i.e. no two objects will be able to lock on that object at the same time).

If the field is non-static, then each instance will have its own lock, so only calls of the method on the same object will lock each other.

When you use a static lock object:

  • thread 1 calls o1.foo()
  • thread 2 calls o1.foo(), will have to wait for thread 1 to finish
  • thread 3 calls o2.foo(), will also have to wait for thread 1 (and probably 2) to finish

When you use a non-static lock object:

  • thread 1 calls o1.foo()
  • thread 2 calls o1.foo(), will have to wait for thread 1 to finish
  • thread 3 calls o2.foo(), it can just continue, not minding thread 1 and 2

Which one of those you'll need depends on what kind of data you try to protect with your synchronized block.

As a rule of thumb, you want the lock-object to have the same static-ness than the operated-on value. So if you manipulate non-static values only, you'll want a non-static lock object. If you manipulate static values only, you'll want a static lock object.

When you manipulate static and non-static values, then it'll become complicated. The easy way would be to just use a static lock object, but that might increase the size of the synchronized-block more than absolutely necessary and might need to more lock contention than desired. In those cases you might need a combination of static and non-static lock objects.

In your particular case you use the lock in the constructor, which will only ever be executed once per instance, so a non-static lock-object doesn't make any sense here.

Difference between class locking and object locking in Java

The only difference is that a static synchronized locks on the class instance and a non-static synchronized method locks on the instance.

People tell about two types of multi-threaded locking

There is object instance locks and Lock style locks. A Lock, confusingly, has both.

object and class

Not true as you have worked out already.

Just because people say stuff doesn't make it true. Often people say a lot of nonsense. In fact there is whole web sites devoted to non-sense about Java. :P



Related Topics



Leave a reply



Submit