在 java 中对对象进行同步,然后更改已同步的变量的值
2022-09-01 21:00:19
我遇到了这样的代码
synchronized(obj) {
obj = new Object();
}
有些事情感觉不对劲,我无法解释,这段代码是OK还是真的有问题,请指出来。谢谢
我遇到了这样的代码
synchronized(obj) {
obj = new Object();
}
有些事情感觉不对劲,我无法解释,这段代码是OK还是真的有问题,请指出来。谢谢
这可能不是你想做的。您正在同步一个不再包含引用的对象。考虑另一个运行此方法的线程:他们可能会在引用更新为指向新对象后进入并尝试按锁定。此时,它们正在与第一个线程不同的对象上进行同步。这可能不是你所期望的。obj
除非您有充分的理由不这样做,否则您可能希望在最终对象上进行同步(为了可见性的缘故)。在这种情况下,您可能希望使用单独的锁变量。例如:
class Foo
{
private final Object lock = new Object();
private Object obj;
public void method()
{
synchronized(lock)
{
obj = new Object();
}
}
}
如果 obj 是一个局部变量,并且没有其他线程正在评估它以获取锁,如下所示,则无关紧要。否则,这将严重损坏,并且以下情况适用:
(发布这个是因为其他答案的措辞不够强烈 - “可能”在这里是不够的 - 并且没有足够的细节。
每当线程遇到同步块时,在获取锁之前,它必须通过计算同步关键字后面的parens中的表达式来确定需要锁定的对象。
如果在线程计算此表达式后更新引用,则线程无法知道这一点。它将继续获取之前标识为锁定的旧对象上的锁定。最终,它会在旧对象上进入同步块锁定,而另一个线程(在锁定更改后尝试进入块)现在将锁定评估为新对象,并输入持有新锁定的同一对象的同一块,并且您没有相互排除。
JLS 中的相关部分是 14.19。执行同步语句的线程:
1) 计算表达式,然后
2) 获取表达式计算结果到的值的锁,然后
3) 执行块。
在成功获取锁时,它不会再次重新访问评估步骤。
此代码已损坏。别这样。锁定不会改变的东西。