Java同步和内存可见性。其他线程可见10吗?

时间:2016-11-04 11:27:18

标签: java multithreading synchronization visibility

我有两节课。

一个类只是一个带有get和set synchronized方法的整数值的容器。

public class Sync {
   private int dataSync;

   public synchronized int getDataSync() {
       return dataSync;
   }

   public synchronized void setDataSync(int data) {
      dataSync = data;
   }
}

其他课程类似。 它只是一个整数值的容器,其get和set方法没有同步。

public class NotSync {

   private int dataNotSync;

   public int getDataNotSync() {
      return dataNotSync;
   }

   public void setDataNotSync(int data) {
      dataNotSync = data;
   }
}

现在我的问题是"保证10个值对所有其他线程可见#34;在run方法结束时。

public class RunSync {

   public static void main(String[] args) {
      RunSync rs = new RunSync();
      rs.run();
   }

   private NotSync dataNS;

   private Sync    dataS;

   private int     data;

   public RunSync() {
      dataS = new Sync();
      dataNS = new NotSync();
   }

   public synchronized void run() {
      data = 100;
      dataS.setDataSync(45);
      dataNS.setDataNotSync(10);
      //Question A: is 10 value guaranteed to be visible to all other
      //threads when method exits?
      //we are inside a synchronized block aren't we? 
      //so all writes must be flushed to main memory
   }
}

编辑:想象一下还有其他线程。这只是一个快速编写的例子。问题是在同步块完成时确切地保证刷新回主存储器。

EDIT2:根据java内存模型 "只有在某些条件下,才能保证一个线程对字段的更改对其他线程可见。一个条件是写入线程释放同步锁,读取线程随后获取相同的同步锁。

因此,如果另一个线程获得RunSync锁定,是否可以保证在RunSync的NotSync实例中看到10?即使NotSync不受保护?

Edit3:没有确定答案的相关问题。我还在寻找。 What is the scope of memory flushed or published to various threads when using volatile and synchronized?

EDIT4:要简化示例,请从RunSync类

中简化此方法
public synchronized void run2() {
    dataNS.setDataNotSync(10);
}

当run2退出时,什么都不能保证刷新到主内存?对此的明确答案将回答我的问题。如果否,这意味着只保证刷新锁定成员,并且对其他线程可见,其他线程在RunSync上获取相同的锁定。 答案是无保证。

EDIT5:在这种情况下,断言是否保证为真?

public class RunSync {

public volatile boolean was10Written = false;

    public synchronized void run2() {
      dataNS.setDataNotSync(10);
      was10Written = true;
   }

   public void insideAnotherThread() {
      if(was10Written) {
         int value = dataNS.getDataNotSync();
         assert value == 10;
      }
   }
}

2 个答案:

答案 0 :(得分:2)

答案是否定的,不保证可见,但可能是。由于10的写入不同步,因此在对同步读取进行排序之前不会发生。

  

根据java内存模型"只有在某些条件下,才能保证一个线程对字段的更改对其他线程可见。

如果一个线程的写入发生在同步操作之前,则为true。写入10后发生,因此没有可见性保证。

例如,如果您有一个新字段并在写入dataSync(同步)之前将其写入10,并且您将dataSync评估为45,那么对新字段的写入将是可见的。

答案 1 :(得分:0)

还有什么其他主题?无论如何,你应该看到关键字volatile for start。同步一个方法也不会同步实例变量进行读/写。因此,如果一个线程正在写入,另一个线程可以读取不同的值,因为只有方法是同步的(一次只有一个线程正在设置值,一个正在读取,但是你可以同时读取/写入同一时间