Hi all whenever I use the synchronized statement, I often use this pattern:
private static Object lock = new Object();
public void F(){
//..
synchronized (lock){
//..
}
//..
}
However, in the source of java.lang.Reference
, I see that they employ this pattern instead:
static private class Lock { };
private static Lock lock = new Lock();
public void run() {
//..
synchronized(lock){
//..
}
//..
}
I was wondering what's the benefit of declaring a new class Lock (which basically extends Object and do nothing else) ?
Or rather, why didn't they simply use private static Lock lock = new Object();
?
The following code:
synchronized(lock){
}
doesn't actually use the Lock
mechanics, you're just using the built-in synchronisation features on an Object
. In this case, you might as well use a plain old Object
. A benefit of a lock object that extends Object
is so that it shows up in debugging tools with the class name rather than just a plain Object
, which is more helpful when hunting down deadlocks.
See here for the Lock
API.
The benefit of Lock
is that you get more features, such as being able to 'try' locking, then continuing to execute code if that fails. Also, it has different properties than a synchronized block, because it's not reentrant (a thread can't hold multiple locks on the same lock, then release them). If you wanted something that was like that, you'd use ReentrantLock
.
You also have cooler locks such as ReentrantReadWriteLock
, which support multiple readers, but as soon as a writer locks it, no readers are permitted. There's a big lock ecosystem in there for different types of application.
I was wondering what's the benefit of declaring a new class Lock (which basically extends Object and do nothing else) ?
Readability. I believe that creating an instance of Object
is at least weird, so having a separate, well named class for that purpose seems like a good idea.
BTW field containing a lock should always be final
, otherwise you are asking for trouble.
The name of the lock object's class appears in thread dumps. This makes it easier to interpret such dumps.
For instance, here is an example using Reference.Lock
. You can see immediate what sort of lock it is and not confuse it with, say, a lock in ReferenceQueue
. This was more important in earlier versions of the Sun JRE where the object identity hash wasn't displayed.
"Reference Handler" daemon prio=10 tid=0x000000000068f400 nid=0xbf5 in Object.wait() [0x000000004055d000..0x000000004055dca0]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00007f651aa10338> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:485)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked <0x00007f651aa10338> (a java.lang.ref.Reference$Lock)
As for
private static Lock lock = new Object();
that doesn't compile (and should be using final
!).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With