在java中同步对象,然后更改synchronized-on变量的值

cod*_*mon 21 java concurrency synchronization

我遇到了这样的代码

synchronized(obj) {

   obj = new Object();

}
Run Code Online (Sandbox Code Playgroud)

有些事情对此感觉不对,我无法解释,这段代码是否正常或者其中有什么问题,请指出.谢谢

Edw*_*son 20

这可能不是你想要做的.您正在同步一个您不再持有引用的对象.考虑另一个运行此方法的线程:它们可能会obj在更新引用之后进入并尝试锁定锁定以指向新对象.此时,它们在与第一个线程不同的对象上进行同步.这可能不是你所期待的.

除非你有充分的理由不这样做,否则你可能想要在最终的Object上进行同步(为了可见性).在这种情况下,你可能想要使用一个单独的锁变量.例如:

class Foo
{
    private final Object lock = new Object();
    private Object obj;

    public void method()
    {
        synchronized(lock)
        {
            obj = new Object();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Nat*_*hes 5

如果 obj 是局部变量并且没有其他线程正在评估它以获取它的锁(如此处所示),那么这并不重要。否则,这将被严重破坏,并且适用以下内容:

(发布此内容是因为其他答案措辞不够强烈——“可能”在这里不够充分——并且没有足够的细节。)

每次线程遇到同步块时,在获取锁之前,它必须通过计算同步关键字后面的括号中的表达式来确定需要锁定哪个对象。

如果在线程计算该表达式之后引用被更新,则线程无法知道这一点。它将继续获取它之前识别为锁的旧对象上的锁。最终它进入旧对象上的同步块锁定,而另一个线程(在锁更改后尝试进入该块)现在将该锁评估为新对象,并进入持有新锁的同一对象的同一块,并且你们没有相互排斥。

JLS 中的相关章节为14.19。执行synchronized语句的线程:

1) 计算表达式,然后

2) 获取表达式计算结果的锁,然后

3) 执行块。

它在成功获取锁时不会再次重新访问评估步骤。

这段代码已损坏。不要这样做。锁定那些不会改变的事情。


ape*_*ins 3

在这种情况下,有人可能认为他们正在做的事情没问题,但这可能不是他们想要的。在本例中,您正在同步 obj 变量中的当前值。一旦创建了一个新实例并将其放入 obj 变量中,锁定条件就会发生变化。如果这就是该块中发生的所有事情,那么它可能会起作用 - 但如果它之后执行任何其他操作,则该对象将无法正确同步。

最好是安全并在包含对象上或完全在另一个互斥体上同步。