【问题标题】:java's object visibility under multiple locks多锁下java的对象可见性
【发布时间】:2014-06-28 17:30:04
【问题描述】:

这是我面临的问题。在运行下面的代码时,我有时会在打印 B 的内容时得到陈旧的数据。我真的不明白为什么会发生这种情况,因为更新和接收 B 的内容受到 B 的锁的保护。

请注意,在更新到 B 期间,A 和 B 的锁都被持有。 在访问 B 的内容时,只持有一个锁。

还要注意 B.updated() 不同步,但我不认为这是问题所在,因为我在访问 B 的内容之前确保更新的计数器设置为 2。

class B {
  Object data
  int updated = 0

  // get and set protected by B's monitor
  synchronized Object getData() {
    return data;
  }
  synchronized setData(Object d) {
    data = d;
    updated += 1;
  }
  // deliberately not synchronized
  int updated() { return updated; }
}

class A {
    B b
    A() {
        new Thread t = new Thread(new UpdaterThread());
        t.start();
    }

   // when B is updated both A and B monitors are held
    synchronized String setB(Object data) {
      b.setData(data);
   }

   class UpdateThread implements Runnable {
     public void run() {
       // updating B to new Value
       setB("B2");
     }
   }
}

public static void main(String[] _) {
   B b = new B();  
   b.setData("B1");
   A a = new A();
   while (b.updated() == 1) {
     // wait for updated to reach 2
   } 
   println(b.getData());  // prints "B1" sometimes, but very rarely.
}

【问题讨论】:

  • 我应该补充一点,这是我目前正在使用的库中的一个高度简化的代码。
  • 别忘了在声明之后加上分号。

标签: java multithreading concurrency visibility locks


【解决方案1】:

您希望代码为sequentially consistent。然而,Java 只保证顺序一致性,前提是代码中没有数据竞争

还要注意 B.updated() 不同步,但我不认为这是问题所在,因为我在访问 B 的内容之前确保更新的计数器设置为 2。

这就是问题所在。您在更新的变量上有一个数据竞争,因为一个线程写入它,另一个线程读取它而没有任何同步。

如果您创建变量volatile,代码将起作用,因为volatile 变量上没有数据竞争

【讨论】:

  • 我认为使变量 volatile 是不够的。 volatile 关键字会将值刷新到主内存,以便在其他线程中可见;但是,我认为它不能保证与其他变量的更新同步。 'updated' 的值仍然可以先被刷新,结果当 data 的值尚未刷新且还不可见时,main() 方法仍然可以看到 b 更新。
猜你喜欢
  • 1970-01-01
  • 2016-12-23
  • 2011-02-23
  • 1970-01-01
  • 2012-03-11
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
  • 2021-02-27
相关资源
最近更新 更多