为什么 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
的缓存副本并错过了更新。
我也明白如果我做 volatile
private 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 = j
和 return i
更改为 return data.i
现在 getI
和 setI
方法不会对定义它们的对象的状态做任何事情(并且可能是同步的)。即使现在使用 synchronized
关键字也会导致程序终止!有趣的是知道其状态实际上正在改变 (Data
) 的对象没有同步或任何内置的东西。那为什么?
[1] 它可能只是 表现,我不清楚实际发生的事情
这只是巧合或依赖于平台或依赖于特定的 JVM,JLS 不保证。所以,不要依赖它。
这个程序没有终止!
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
的缓存副本并错过了更新。
我也明白如果我做 volatile
private 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 = j
和 更改为 return i
return data.i
现在 getI
和 setI
方法不会对定义它们的对象的状态做任何事情(并且可能是同步的)。即使现在使用 synchronized
关键字也会导致程序终止!有趣的是知道其状态实际上正在改变 (Data
) 的对象没有同步或任何内置的东西。那为什么?
[1] 它可能只是 表现,我不清楚实际发生的事情
这只是巧合或依赖于平台或依赖于特定的 JVM,JLS 不保证。所以,不要依赖它。