![](/img/trans.png)
[英]Happens-before relationships with volatile fields and synchronized blocks in Java - and their impact on non-volatile variables?
[英]Volatile happens-before relationship when there's mix of volatile and non-volatile fields
當易失性和非易失性字段混合時,我試圖了解易失性字段的發生前行為。
假設有 1 個 WriteThread 和 5 個 ReadThreads,它們更新/讀取 SharedObject。
ReadThreads 從一開始就調用方法waitToBeStopped()
,WriteThread 在 1 秒后調用方法stop()
。
public class SharedObject {
volatile boolean stopRequested = false;
int a = 0, b = 0, c = 0;
int d = 0, e = 0, f = 0;
// WriteThread calls this method
public void stop() {
a = 1;
b = 2;
c = 3;
stopRequested = true;
a = 4;
b = 5;
c = 6;
d = 7;
e = 8;
f = 9;
}
// ReadThread calls this method
public void waitToBeStopped() throws Exception {
while(!stopRequested) {
}
System.out.println("Stopped now.");
System.out.println(a + " " + b + " " + c + " " + d + " " + e + " " + f);
}
}
當這個程序結束時,output 是這樣的。 即使我嘗試了 100 多個 ReadThreads,結果也總是一樣的。
Stopped now.
Stopped now.
Stopped now.
Stopped now.
Stopped now.
4 5 6 7 8 9
4 5 6 7 8 9
4 5 6 7 8 9
4 5 6 7 8 9
4 5 6 7 8 9
Q1。 有人可以解釋為什么這總是返回 4,5,6,7,8,9 而不是 1,2,3,0,0,0?
我對happens-before關系的理解是這樣的:
a=1,b=2,c=3
發生在WriteThread 寫入stopRequested
之前stopRequested
發生在WriteThread 寫入a=4,b=5,c=6,d=7,e=8,f=9
之前stopRequested
發生在ReadThread 讀取stopRequested
之前stopRequested
發生在ReadThread 讀取a,b,c,d,e,f
之前從這 4 個陳述中,我無法得出這樣的陳述……
a=4,b=5,c=6,d=7,e=8,f=9
發生在ReadThread 讀取a,b,c,d,e,f
之前如果有幫助,這是代碼的另一部分:
public class App {
public static void main(String[] args) throws Exception {
SharedObject sharedObject = new SharedObject();
for(int i =0 ; i < 5; i++) {
Runnable rThread = new ReadThread(sharedObject);
new Thread(rThread).start();
}
Runnable wThread = new WriteThread(sharedObject);
new Thread(wThread).start();
}
}
public class WriteThread implements Runnable {
private SharedObject sharedObject;
public WriteThread(SharedObject sharedObject) {
this.sharedObject = sharedObject;
}
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
sharedObject.stop();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class ReadThread implements Runnable {
private SharedObject sharedObject;
public ReadThread(SharedObject sharedObject) {
this.sharedObject = sharedObject;
}
public void run() {
try {
sharedObject.waitToBeStopped();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
您假設stopRequested = true;
不保證對讀者可見是正確的。 編寫者沒有保證將這些寫入寫入共享緩存/內存,在這些緩存/內存中它們對讀者可見。 它可以將它們寫入本地緩存,而讀者不會看到更新的值。
Java語言保證了可見性,例如當您使用 volatile 變量時。 但它不保證非易失性變量上的更改對其他線程不可見。 在您的情況下,此類寫入仍然可以看到。 處理器的 JVM 實現、memory 一致性 model 和其他方面影響可見性。
請注意,JLS 和happens-before 關系是一個規范。 JVM 實現和硬件通常比 JLS 指定的更多,這可能導致 JLS 不需要可見的寫入可見性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.