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

在java中对对象进行同步,然后更改synchronized on变量的值,java,concurrency,synchronization,synchronized,Java,Concurrency,Synchronization,Synchronized,我遇到了这样的代码 synchronized(obj) { obj = new Object(); } 我无法解释,这段代码是否正确,或者其中确实有错误,请指出。 谢谢在这种情况下,有些人可能会认为他们正在做的是可以的,但这可能不是他们想要的。在这种情况下,您正在同步obj变量中的当前值。创建新实例并将其放入obj变量后,锁定条件将更改。如果这就是这个块中发生的所有事情,它可能会工作——但是如果它在之后做任何其他事情,对象将不会正确同步 最好是安全地在包含对象上同步,或者完全在另一个

我遇到了这样的代码

synchronized(obj) {

   obj = new Object();

}
我无法解释,这段代码是否正确,或者其中确实有错误,请指出。
谢谢

在这种情况下,有些人可能会认为他们正在做的是可以的,但这可能不是他们想要的。在这种情况下,您正在同步obj变量中的当前值。创建新实例并将其放入obj变量后,锁定条件将更改。如果这就是这个块中发生的所有事情,它可能会工作——但是如果它在之后做任何其他事情,对象将不会正确同步


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

这可能不是您想要做的。您正在一个不再持有引用的对象上进行同步。考虑运行此方法的另一个线程:在引用到<代码> Obj>代码>之后,它们可以进入并尝试击中锁,以更新指向新对象。此时,它们正在与第一个线程不同的对象上同步。这可能不是你所期望的

除非您有充分的理由不这样做,否则您可能希望在最终对象上进行同步(为了可见性)。在这种情况下,您可能希望使用单独的锁变量。例如:

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

    public void method()
    {
        synchronized(lock)
        {
            obj = new Object();
        }
    }
}

如果obj是一个局部变量,并且没有其他线程对其求值以获取锁,那么它就无关紧要了。否则,这将严重损坏,以下情况适用:

(发布此消息是因为其他答案的措辞不够强硬——“可能”在这里不够,而且没有足够的细节。)

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

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

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

1) 计算表达式,然后

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

3) 执行块

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


这个密码坏了。不要这样做。锁定不变的事物。

这是一种不常见的用法,但在相同的场景中似乎有效。我在JmDNS的代码库中找到了一个:

public Collection<? extends DNSEntry> getDNSEntryList(String name) {
    Collection<? extends DNSEntry> entryList = this._getDNSEntryList(name);
    if (entryList != null) {
        synchronized (entryList) {
            entryList = new ArrayList<DNSEntry>(entryList);
        }
    } else {
        entryList = Collections.emptyList();
    }
    return entryList;
}

public Collection此代码的输出是什么?您应该只锁定
final
字段以避免执行此操作。这是个坏主意。