With Java instruction reordering the execution order of the code is changed by the JVM at compile time or run time, possibly causing unrelated statements to be executed out-of-o
I wrote a JUnit 5 test that checks whether instruction reordering took place after two threads terminate.
public class InstructionReorderingTest {
static int x, y, a, b;
@org.junit.jupiter.api.BeforeEach
public void init() {
x = y = a = b = 0;
}
@org.junit.jupiter.api.Test
public void test() throws InterruptedException {
Thread threadA = new Thread(() -> {
a = 1;
x = b;
});
Thread threadB = new Thread(() -> {
b = 1;
y = a;
});
threadA.start();
threadB.start();
threadA.join();
threadB.join();
org.junit.jupiter.api.Assertions.assertFalse(x == 0 && y == 0);
}
}
I ran the test until it fails several times. The results are as follows:
InstructionReorderingTest.test [*] (12s 222ms): 29144 total, 1 failed, 29143 passed.
InstructionReorderingTest.test [*] (26s 678ms): 69513 total, 1 failed, 69512 passed.
InstructionReorderingTest.test [*] (12s 161ms): 27878 total, 1 failed, 27877 passed.
The results we expect are
x = 0, y = 1: threadA runs to completion before threadB starts.x = 1, y = 0: threadB runs to completion before threadA starts.x = 1, y = 1: their instructions are interleaved.No one can expect x = 0, y = 0, which may happen as the test results showed.
The actions in each thread have no dataflow dependence on each other, and accordingly can be executed out of order. (Even if they are executed in order, the timing by which caches are flushed to main memory can make it appear, from the perspective of
threadB, that the assignments inthreadAoccurred in the opposite order.)Java Concurrency in Practice, Brian Goetz