大家好,每当我使用synchronized语句时,我经常使用这种模式:
private static Object lock = new Object();
public void F(){
//..
synchronized (lock){
//..
}
//..
}
然而,在java.lang.Reference
的来源中,我看到他们采用这种模式:
static private class Lock { };
private static Lock lock = new Lock();
public void run() {
//..
synchronized(lock){
//..
}
//..
}
我想知道声明一个新类Lock的好处是什么(它基本上扩展了Object并且什么都不做)?
或者更确切地说,为什么他们不使用private static Lock lock = new Object();
?
答案 0 :(得分:5)
以下代码:
synchronized(lock){
}
实际上并未使用Lock
机制,您只需使用Object
上的内置同步功能。在这种情况下,您也可以使用普通的旧Object
。扩展Object
的锁对象的好处是它在调试工具中显示的是类名,而不仅仅是普通的Object
,这在追捕死锁时更有用。
请参阅here了解Lock
API。
Lock
的好处是,您可以获得更多功能,例如能够尝试“尝试”。锁定,然后继续执行代码,如果失败。此外,它具有与同步块不同的属性,因为它不可重入(线程不能在同一个锁上保持多个锁,然后释放它们)。如果你想要那样的东西,你可以使用ReentrantLock
。
你也有ReentrantReadWriteLock
等冷却器锁,它支持多个读卡器,但只要作者锁定它,就不允许读者使用。对于不同类型的应用,那里有一个很大的锁定生态系统。
答案 1 :(得分:4)
我想知道声明一个新类Lock的好处是什么(它基本上扩展了Object并且什么都不做)?
可读性。我认为创建Object
的实例至少是奇怪的,所以为此目的设置一个单独的,名字很好的类似乎是个好主意。
包含锁定的BTW字段应始终为final
,否则您会遇到麻烦。
答案 2 :(得分:1)
锁定对象类的名称显示在线程转储中。这样可以更轻松地解释此类转储。
例如,here是使用Reference.Lock
的示例。你可以立即看到它是什么类型的锁,而不是把它与ReferenceQueue
中的锁相混淆。这在Sun JRE的早期版本中更为重要,其中未显示对象标识哈希。
"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)
至于
private static Lock lock = new Object();
不编译(应该使用final
!)。