java在多个锁下的对象可见性

RD.*_*RD. 1 java concurrency multithreading visibility locks

这是我面临的问题.在运行下面的代码时,我有时会在打印B的内容时收到过时的数据.我无法理解为什么会发生这种情况,因为更新和接收B的内容受B锁的保护.

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

另请注意,B.updated()未同步,但我不认为这是问题,因为我确保更新的计数器设置为2,然后才访问B的内容.

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.
}
Run Code Online (Sandbox Code Playgroud)

nos*_*sid 5

您期望代码顺序一致.但是,如果代码中没有数据争用,Java 仅保证顺序一致性.

另请注意,B.updated()未同步,但我不认为这是问题,因为我确保更新的计数器设置为2,然后才访问B的内容.

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

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