为什么 synchronized getter 像 volatile read 一样工作?

Why a synchronized getter work like a volatile read?

这个程序没有终止!

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!");
  } 
}

我知道发生这种情况是因为 CPU 核心 运行 Awaiting 循环总是看到 i 的缓存副本并错过了更新。

我也明白如果我做 volatileprivate int i = 0; 那么 while (getI()... 会表现 [1] 好像每次它都在查询主内存 - 所以它会看到更新后的值并且我的程序将终止。

我的问题是:如果我

synchronized private int getI() {return i; }

效果出乎意料!!程序终止。

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

编辑 1

This (synchronization) guarantees that changes to the state of the object are visible to all threads

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

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

现在 getIsetI 方法不会对定义它们的对象的状态做任何事情(并且可能是同步的)。即使现在使用 synchronized 关键字也会导致程序终止!有趣的是知道其状态实际上正在改变 (Data) 的对象没有同步或任何内置的东西。那为什么?


[1] 它可能只是 表现,我不清楚实际发生的事情

这只是巧合或依赖于平台或依赖于特定的 JVM,JLS 不保证。所以,不要依赖它。