我正在工作中修改一些并发代码,最近阅读了关于内在锁和同步的Java文档。
鉴于每个对象都有一个内在锁,为什么我要创建一个单独的对象来控制对特定项目的访问?
我认识到可能有一个用例,其中感兴趣的项目不是
malloc
'd Object
,(int
vs Integer
),因此没有内在锁,但是......假设我们担心同步一些static Object
,有什么损失吗?
例如:
public class main {
public static void main (String[] args){
Integer foo = 10;
synchronized(foo){
foo ++;
}
}
}
如果我想从多个线程同步更新
foo
,为什么我不直接使用我想要修改的对象呢?这是性能较低吗?我看到很多 synchronized(this)
,以及我们可以出于同步目的创建锁定对象的单独实例:
public class main {
public static void main (String[] args){
Integer foo = 10;
Object fooLock = new Object();
synchronized(fooLock){
foo ++;
}
}
}
当我可以使用实际感兴趣的对象时,为什么我要创建
fooLock
?这实际上是不鼓励的(不是惯用的),还是有实际的理由不这样做?
我正在考虑对
synchronized(foo)
套接字连接对象执行第一种方法(static
),但令我担心的是我还没有看到对此的讨论。我是不是错过了什么?
这是一条评论,不是对您问题的回答。
你的两个例子并不等同。第二个可以防止多个线程*同时进入
synchronized
块,但第一个可以允许多个线程同时进入该块。
那是因为,在第一个中,
synchronized(foo)
锁定了Integer
变量在给定时刻恰好引用的任何一个foo
对象,但是foo++
语句重新分配了foo
,以便它引用一个不同的对象。不同的线程可以同时位于块中,每个线程在不同的对象上同步。
在第二个示例中,
fooLock
是有效地不可变的。它始终引用同一个 Object
实例。由于每个线程都尝试与其他线程同步同一对象,因此它们将被迫一次遍历一个块。
* 实际上,您的两个示例都是完整的程序,从不创建任何新线程。在我的评论中,我想象如果您的
main(...)
函数的主体实际上位于某个较大程序中的许多线程调用的其他函数中,会发生什么。