Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

About reordering: Why this code throws RuntimeException despite using the volatile?

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;
    }
}

The assignments of one, two and three may be reordered, as long as they all happen before the volatile write. Similarly, the x, y, and z statements may be reordered as the volatile write happens before all of them. The volatile operation is often called a memory barrier. The happens before guarantee ensures that read and write instructions of volatile variables cannot be reordered across a memory barrier.

The happens before guarantee has another effect: When a thread writes to a volatile variable, then all other variables - including non-volatiles - changed by the thread before writing to the volatile variable are also flushed to main memory. When a thread reads a volatile variable it also reads all other variables - including non-volatile - that were flushed to main memory together with the volatile variable.

© Bruce Eckel "On Java 8"

I must have misunderstood something because this code doesn't work like this

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();
        }
    }
}
like image 947
Sergey Gornostaev Avatar asked Jul 12 '18 09:07

Sergey Gornostaev


1 Answers

I think, the problem can occur when the writer tread has just set x=1, while the reader is already in the if block (before the variable assignments):

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
like image 96
TmTron Avatar answered Oct 10 '22 17:10

TmTron