请看这个答案。它说:
六个最糟糕的例子;
...
在可变字段上锁定。例如 synchronized(object) { object = ...; }
在可变字段上锁定有什么问题?如果object
声明为final
,但它不是一个不可变类呢?
请看这个答案。它说:
六个最糟糕的例子;
...
在可变字段上锁定。例如 synchronized(object) { object = ...; }
在可变字段上锁定有什么问题?如果object
声明为final
,但它不是一个不可变类呢?
这是一个不好的想法,因为如果另一个线程在关键部分更改了引用,那么线程将不再看到相同的引用,因此它们将不会同步在同一对象上,从而运行不受控制。 例如:
synchronized(lock1) {
lock1 = new Object();
sharedVariable++;
}
假设有2个线程试图进入此关键部分。线程1进入并等待线程2。线程1进入,重新分配lock1
并继续执行。现在线程2看到的锁与线程1获取的不同,也是空闲的,因此它也可以进入关键部分。乐趣开始!
如果该对象是final
,则无法将引用重新分配给另一个对象,因此上述问题不再适用。
这里“可变”不是正确的词语。锁定可变对象即有状态的对象是可以的,但是在锁定字段、更改它并期望另一个线程锁定同一对象时就是错误的。
我认为锁定可变对象本身并不是一件坏事。只是很难做到正确。还有其他的并发处理模型,比如演员模型。我建议你去了解一下 Akka,它可以从 Java 和 Scala 两种语言使用,并且是一个非常稳定的实现。