我試圖調查在java環境中重新排序(使用JDK 9-ea + 170)的行爲,並發現我無法爲自己解釋的一件事,所以我很樂意聽到關於它的一些說明。下面是一個例子:爲什麼使用兩個volatile變量重新排序?
public class Client {
int x;
int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
這個方案有一個test()
方法,該方法只是增加x和y值。我正在創建新的線程,並調用此test()
,直到某些內部java優化不會更改x++; y++;
指令()的順序。這樣我證明重新排序確實發生。程序大部分時間結束(這是預期的)。 現在我已經加入volatile修飾符到Y:
public class Client {
int x;
volatile int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
這個程序永遠不會結束,因爲揮發性保證了所有的前揮發的指令會被衝入所以x++;
總是y++;
之前執行的內存,這是不可能有y> x。這也是我的理解所期待的。但在那之後我已經添加揮發性到int x;
過,現在我可以再次看到重新排序,從而程序結束大部分的時間:
public class Client {
volatile int x;
volatile int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
爲什麼這裏的重新排序也發生?
能否請您提供一個例子怎麼可能是B> A? 在上面描述的流程中,賦值給A發生在賦值給B之前。 –
1)變量是'x'和'y'。 'A'和'B'表示線程。 2)所有需要發生的事情是,你在'x'上的損失比在'y'上損失更多,然後'y <= x'將會是'false'。 –
感謝您的更新!現在對我來說有點乾淨了。斯蒂芬,現在我運行相同的代碼,但在test()上使用同步關鍵字。它在volatile或y和x和y上工作正常,但在沒有volatile的情況下(這是預期的)失敗並且僅在x上volatile時失敗。這是正常的行爲嗎?請解釋你是否知道發生了什麼 –