Here's a good puzzle for Java lovers.
John Programmer had a Java program. The program never printed anything to the console, no matter how many times he ran it. He decided to clean up the code a bit. Somewhere in the middle of the program John saw this line:
x = x;
He removed it.
When he reran the program, he saw this text printed to the console: "Error."
Can you recreate John's program?
Hint: this is not about syntax tricks with curly braces. This is about Java semantics.
Time for another hint. The program also had these lines:
if (x == 0 && y == 1 && z == 2)
System.out.println("Error.");
Dmitri Plotnikov - 2015-12-20 17:13:58-0500
Anonymous sent me the correct answer.
Here it is:
volatile int x = 0;
int y = 0;
int z = 2;
// on Thread A:
z = 3;
x = x;
y = 1;
// on Thread B:
if (x == 0 && y == 1 && z == 2)
System.out.println("Error.");
The Java Memory Model allows variables y and z to be stored in temporary caches or CPU registers. Since x
is declared as volatile, setting its value creates a memory barrier . This means that any changes to x
and other variables, including y
and z
, are committed from any CPU registers or cache to the main memory. This guarantees that the new value of z (3)
becomes visible to Thread B before the new value of y (1)
. The condition y == 1 && z == 2
is always false.
In the absence of "x = x"
, the order in which changes to y
and z
become visible to Thread B is unpredictable. Variable y
may be changed to 1
before variable z
is changed to 3
. This reordering may be done by the Java compiler or the JIT compiler or by the hardware. The order in which the values are flushed to the main memory by one thread and read from the main memory by the other thread is undefined. This is not a hypothetical possibility: compilers and optimizers routinely reorder operations; and caches are flushed in unpredictable order.
To ensure the correct order of changes, it is important to both store the volatile variable on Thread A (x = x
) and also read it on Thread B (x == 0
). The former operation flushes cached values to the main memory. The latter invalidates any cached values that Thread B may have used.
You can read all about it here: https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
Dmitri Plotnikov - 2015-12-21 12:10:44-0500
My deepest apologies to both Joe Programmer and John Programmer for mixing them up! Of course it is Joe who programs in Java.
And, for the record, I agree with Anonymous 100%. Using "volatile" or accessing variables across threads without any synchronization is a game of chance, meaning that chances are you'll get it wrong.