关于重新排序:尽管使用volatile,为什么此代码会抛出RuntimeException?

Ser*_*aev 5 java multithreading java-memory-model

public class ReOrdering implements Runnable {
    int one, two, three, four, five, six;
    volatile int volaTile;

    @Override
    public void run() {
        one = 1;
        two = 2;
        three = 3;
        volaTile = 92;
        int x = four;
        int y = five;
        int z = six;
    }
}
Run Code Online (Sandbox Code Playgroud)

的任务one,two并且three可以重新排序,只要他们所有发生之前volatile写.同样,x,yz 作为陈述可能被重新排序volatile写个个之前发生.该volatile操作通常称为内存屏障.保证之前发生的事情确保volatile变量的读写指令 不能在内存屏障上重新排序.

在保证具有另一种效果之前发生:当线程写入volatile变量时,在写入volatile 变量之前由线程更改的所有其他变量(包括非易失性)也会刷新到主存储器.当线程读取 volatile变量时,它还会读取所有其他变量(包括非易失性),这些volatile变量与变量一起刷新到主存储器 .

©Bruce Eckel"On Java 8"

我一定是误解了一些东西,因为这段代码不能像这样工作

public class Reordering {
    private int x;
    private volatile int y;

    public void writer() {
        x = 1;
        y = 2;
    }

    public void reader() {
        if (y == 2) {
            if(x == 0) {
                // X assignment is happens-before for
                // volatile Y assignment
                // so X can't be 0 when Y equals 2
                throw new RuntimeException();
            }

            x = 0;
            y = 0;
        }
    }

    public static void main(String[] args) {
        Reordering reordering = new Reordering();

        Thread thread = new Thread(() -> {
            while (true) {
                reordering.writer();
            }
        });

        thread.setDaemon(true);
        thread.start();

        while (true) {
            reordering.reader();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

TmT*_*ron 5

我认为,当编写器踏板刚刚设置时,问题可能发生x=1,而读取器已经在if块中(在变量赋值之前):

reader             writer state
-----------------  ------ --------
stops before x=0          x=1, y=2
                   x=1    x=1, y=2
x=0                       x=0, y=2
y=0                       x=0, y=0
                   y=2    x=0, y=2
reader will throw
Run Code Online (Sandbox Code Playgroud)