簡體   English   中英

為什么易失性發生 - 在指令重新排序之前失敗?

[英]Why the volatile Happens-Before order for Instruction Reordering fails?

我hava遵循代碼來測試volatile bEndnCount定義為volatile。

nCount = 0, bEnd = false

Writer線程將設置

nCount = 100, bEnd = true

Reader線程讀取這些變量並打印它們。 基於Java Happens-before命令,在我看來, 當bEnd = true時volatile確保nCount = 100 但有時程序打印這個:

main thread done.
thread Reader running ...
thread Writer running ...
SharedData nCount = 0, bEnd = false
thread Writer bEnd = true
thread Reader nCount = 0, bEnd = true
thread Reader nCount = 100, bEnd = true
thread Reader nCount = 100, bEnd = true
thread Reader done.

Reader如何得到“nCount = 0,bEnd = true” ???

以下代碼在windows10,jdk1.8.0_131上運行

public class HappensBeforeWithVolatile {

    public static void main(String[] args) {

        Thread threadWriter = new Thread(new Writer());
        Thread threadReader = new Thread(new Reader());
        threadWriter.start();
        threadReader.start();

        System.out.println("main thread done.");
    }
}

class Writer implements Runnable {

    @Override
    public void run() {
        System.out.println("thread Writer running ...");
        SharedData.nCount = 100;
//        System.out.println("thread Writer nCount = 100");
        SharedData.bEnd = true;
        System.out.println("thread Writer bEnd = true");
    }
}

class Reader implements Runnable {

    @Override
    public void run() {
        System.out.println("thread Reader running ...");
        System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
        System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
        if (SharedData.nCount == 0 && SharedData.bEnd) {
            System.out.println("thread Reader CODE REORDER !!!");
        }
        System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
        System.out.println("thread Reader done.");
    }
}

class SharedData {
    volatile public static boolean bEnd = false;
    volatile public static int nCount = 0;

    static {
        System.out.println("SharedData nCount = " + nCount + ", bEnd = " + bEnd);
    }
}

當bEnd = true時,volatile確保nCount = 100

技術上,是的。 但是讀者並沒有原子地閱讀它們。 因此它可能會打印nCount = 0 and bEnd = true

這是一個例子:

  1. 讀者讀取nCount 0
  2. Wirter寫nCount = 100
  3. Wirter寫入bEnd bEnd = true
  4. Writer打印thread Writer bEnd = true
  5. 讀者讀取bEnd true

你的整個例子有點瑕疵。 要測試之前發生的情況,您需要測試后續操作,即使bEnd volatile和nCount不是volatile,然后將您的示例簡化為:

static class Reader implements Runnable {
    @Override
    public void run() {

        while (true) {
            if (SharedData.bEnd) {
                System.out.println(SharedData.nCount);
                break;
            } else {
                System.out.println("Not yet seen as true");
                LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
            }
        }
    }
}

static class Writer implements Runnable {
    @Override
    public void run() {
        LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
        SharedData.nCount = 100;
        SharedData.bEnd = true;

    }
}

這將輸出100 ,總是(至少在這種情況下)。 正確的解釋是,如果Reader Thread看到volatile變量的Write線程的更新,它將看到之前完成的所有事情,因此100

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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