[英]Volatile variable and non volatile reordering / visibility
因此,我以為我對這方面的知識已經足夠了解了,直到我讀了一些東西,使我懷疑我對此主題的了解。 我幾乎可以肯定這本書是不正確的,但也想問一下社區。
PS:尚未看到該書的勘誤表,因此很可能被公開為錯誤。
一個簡化的例子:
public class VolatileMain {
private volatile int a = 0;
private String text = "";
public static void main(String[] args) throws Exception {
VolatileMain vm = new VolatileMain();
Thread writer = new Thread() {
@Override
public void run() {
System.out.println("Running thread " + Thread.currentThread().getName());
vm.text = "hello world";
vm.a = 5;
}
};
writer.start();
writer.join();
System.out.println("Running thread " + Thread.currentThread().getName());
System.out.println(vm.a);
System.out.println(vm.text);
}
}
因此,以給出的示例為前提,假設可以保證任何其他讀取該線程的線程都可以看到Thread writer對“文本”的寫入是否正確?
看來作者很支持變量“ a”的易變語義,並確保當刷新“ a”時也刷新對“ text”的寫操作,這是否可以保證?
我不認為是這樣,但是我自己的快速測試(上面)與此相反
你的意見。
假設由線程編寫器對“文本”的寫入保證可以被任何其他讀取它的線程可見,是否正確?
不會。但是可以保證任何其他讀取a
線程在讀取text
之前都可見,如您的示例所示:
text
發生在寫入線程中寫入a
之前 a
在作家的之前發生的讀取a
在主線程 text
的讀取之前發生a
。 不,不能保證,因為“沖洗”不是那么簡單。 即使您實際上將非易失性內容寫入“主內存”,也不能保證其他線程的后續讀取操作也會從該主內存中讀取它。 考慮以下示例:
public class VolatileMain {
private volatile int a = 0;
private String text = "";
public static void main(String[] args) throws Exception {
VolatileMain vm = new VolatileMain();
Thread writer = new Thread() {
@Override
public void run() {
// Added sleep here, so waitForText method has chance to JIT-compile
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
System.out.println("Running thread " + Thread.currentThread().getName());
vm.text = "hello world";
vm.a = 5;
System.out.println("Text changed!");
}
};
writer.start();
waitForText(vm);
writer.join();
System.out.println("Running thread " + Thread.currentThread().getName());
System.out.println(vm.a);
System.out.println(vm.text);
}
// Wait for text change in the spin-loop
private static void waitForText(VolatileMain vm) {
int i = 0;
/*
@Edit by Soner
Compiler may do following steps to optimize in lieu.
String myCache = vm.text;
-- Assume that here myCache is "" -- so stay forever.
while (myCache.equals("")) { i++; }
*/
while (vm.text.equals("")) {
i++;
}
System.out.println("Wait complete: " + i);
}
}
僅因為JIT編譯器會優化它並將vm.text
的讀取移出循環(因為它不是易失性的,所以在循環中不執行易失性讀取並且text
永遠不會更改), waitForText
可能永遠不會完成在循環內)使循環無限。
易失的讀/寫操作不僅會影響內存分配,還會更改JIT編譯策略。 在while循環中添加vm.a
讀取,程序將正常運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.