簡體   English   中英

易失性和非易失性字段混合時發生易失性關系

[英]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關系的理解是這樣的:

  • WriteThread 寫入a=1,b=2,c=3發生在WriteThread 寫入stopRequested之前
  • WriteThread 寫入stopRequested發生在WriteThread 寫入a=4,b=5,c=6,d=7,e=8,f=9之前
  • WriteThread 寫入stopRequested發生在ReadThread 讀取stopRequested之前
  • ReadThread 讀取stopRequested發生在ReadThread 讀取a,b,c,d,e,f之前

從這 4 個陳述中,我無法得出這樣的陳述……

  • WriteThread 寫入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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM