该程序不会终止!
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.i
和getI
方法对定义它们的对象的状态不做任何事情(并且可以被同步)。即使现在使用setI
关键字也会导致程序终止!有趣之处在于知道其状态实际上正在更改(synchronized
)的对象没有同步或任何内置的对象。那为什么呢?
[1] 可能只是表现,因为我不清楚实际上到底发生了什么
答案 0 :(得分:2)
这仅仅是巧合,平台相关性或特定的JVM相关性,JLS不能保证。因此,请不要依赖它。