我有以下代码来测试 volatile bEndnCount定义为volatile。

nCount = 0, bEnd = false

Writer线程将设置
nCount = 100, bEnd = true

Reader线程读取这些可变项并进行打印。我认为,基于Java发生在先的顺序,当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.

读者如何获得“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);
    }
}

最佳答案

volatile确保当bEnd = true时nCount = 100

从技术上讲,是的。但是读者并没有原子地阅读它们。因此它可能会打印nCount = 0 and bEnd = true

这是一个例子:

  • 阅读器读取nCount 0
  • Wirter编写nCount = 100
  • Wirter编写bEnd = true
  • Writer打印thread Writer bEnd = true
  • 阅读器读取bEnd true
  • 10-07 20:12