为什么同步的吸气剂像易失性读一样工作?

时间:2019-01-16 13:43:04

标签: java multithreading synchronized volatile

该程序不会终止!

public class Main extends Thread {
  private int i = 0;
  private int getI() {return i; }
  private void setI(int j) {i = j; }

  public static void main(String[] args) throws InterruptedException {
    Main main = new Main();
    main.start();

    Thread.sleep(1000);
    main.setI(10);
  }

  public void run() {
    System.out.println("Awaiting...");
    while (getI() == 0) ;
    System.out.println("Done!");
  } 
}

我知道发生这种情况是因为运行Awaiting循环的CPU内核始终会看到i的缓存副本,而错过了更新。

我也了解,如果我做出 volatile private int i = 0;,则while (getI()...的行为会像每次一样 [1] 它正在查询主内存-因此它将看到更新的值,并且我的程序将终止。

我的问题是:如果我这样做

synchronized private int getI() {return i; }

它出奇地有效!!该程序终止。

我知道synchronized用于防止两个不同的线程同时进入一个方法-但是这里只有一个线程曾经进入getI()。那这是什么法术?

编辑1

  

(同步)保证对对象状态的更改对所有线程可见

因此,我没有直接拥有私有状态字段i,而是进行了以下更改:

我做了private int i = 0;,代替了 private Data data = new Data(); i = j 更改为data.i = j { {1}} 更改为return i

现在return data.igetI方法对定义它们的对象的状态不做任何事情(并且可以被同步)。即使现在使用setI关键字也会导致程序终止!有趣之处在于知道其状态实际上正在更改(synchronized)的对象没有同步或任何内置的对象。那为什么呢?


[1] 可能只是表现,因为我不清楚实际上到底发生了什么

1 个答案:

答案 0 :(得分:2)

这仅仅是巧合,平台相关性或特定的JVM相关性,JLS不能保证。因此,请不要依赖它。