java - 在非最终对象上同步

标签 java synchronize

<分区>

private volatile Object obj = new MyObject();
void foo() 
{
  synchronized(obj)
  {
    obj.doWork();
  }
}
void bar()
{
  synchronized(obj)
  {
    obj.doWork();
    obj = new MyObject(); // <<<< notice this line (call it line-x)
  }
}

假设在某个时间点,一个线程t_bar正在执行bar(),另一个线程t_foo正在执行 foo,而 t_bar 刚刚获取了 obj,因此 t_foo 实际上在等待。

bar 中的同步块(synchronized block)执行后,foo 将开始执行其同步块(synchronized block),对吗?它会看到 obj 的什么值?旧的?还是 bar 中的新设置?

(我希望看到新值,这就是以这种方式编码的全部意义所在,但我想知道这是否是一个“安全”的赌注)

最佳答案

在您描述的确切情况下,是的,读取 foo 的同步块(synchronized block)内的 obj 将看到由前一个 bar 的同步块(synchronized block)设置的新值。

有趣的是,它并不总是在那种情况下发生。该程序不是线程安全的,例如,如果 bar() 退出后,同一线程立即调用另一个 bar(),而 foo 线程锁定在旧线程上目的。 bar 线程锁定了新对象,因此两个线程并发执行,都在同一个新对象上执行 obj.doWork()

我们可能可以部分修复它

// suppose this line happens-before foo()/bar() calls
MyObject obj = new MyObject();

void foo()
    while(true)
        MyObject tmp1 = obj;
        synchronized(tmp1)
            MyObject tmp2 = obj;
            if(tmp2==tmp1)
                tmp2.doWork();
                return;
            // else retry

这至少保证当前不会在同一个 obj 上调用 obj.doWork(),因为 obj.doWork() 只能发生在锁定的同步块(synchronized block)中完全相同的 obj

关于java - 在非最终对象上同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16241196/

相关文章:

java - Android - 将 .class 传递给 AsyncTask 以与 Gson 一起使用

java - 如何检查任何输入的字符串是否采用任何特定格式(###.#)

java - 如何在java中单向同步两个目录结构中的文件?

java - Tomcat启动失败: the port X is already in used?如何解决

java - Macrodef 未正确传达退出状态

java - 循环标记器和记事本显示

Java JScrollPane 有时无法成功调整大小

multithreading - 如何在Delphi XE7中同步TParallell以记录数据

file - 如何将SVG动画文件与音频文件同步?

java - 如果可以使用synchronized(this),为什么还要使用ReentrantLock?