Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java compiler reordering

Today I read java interview questions and I read this question: Question : Consider the following Java code snippet, which is initializing two variables and both are not volatile, and two threads T1 and T2 are modifying these values as following, both are not synchronized

int x = 0;
boolean bExit = false;

Thread 1 (not synchronized)
x = 1; 
bExit = true;

Thread 2 (not synchronized)
if (bExit == true) 
System.out.println("x=" + x);

Now tell us, is it possible for Thread 2 to print “x=0”?

So, the answer is "yes". In the explanation there is "because without any instruction to compiler e.g. synchronized or volatile, bExit=true might come before x=1 in compiler reordering." Before that I don't know that the compiler can execute one line before another line after it.

Why is this reordering ? And what if I print something to the console from different thread - the line that is supposed to be print first will be print after the line that is supposed to be print second (if they are printed from the same thread) ? It's weird to me (maybe, because I saw this thing for reordering for the first time). Can someone give some explanation ?

like image 362
DPM Avatar asked Jun 23 '15 23:06

DPM


1 Answers

The JIT compiler* can change the order of execution if it won't change the result according to the Java standard. Switching

x = 1;
bExit = true;

to

bExit = true;
x = 1;

does not change the result because there is no synchronization, ie. according to the standard, these variables should not be read by another thread while doing this, and neither of these statements need the other variable. (On modern CPUs, both commands will in fact be executed at the same time which of course means it is unspecified which will be changed first.)

Not only reordering can cause that behavior. It may happen that bExit can be in one memory page and x in another and if the application is running on a multi-processor (or multi-core) system, then without synchronization, it can happen that memory page with bExit will be committed (and changes to it will be visible in all other cores) before memory page with x.

*Edit: Java compiler (compiling .java into .class) cannot change in-thread execution order but JIT compiler (compiling .class into binary code) can. However Java compiler can omit some statements if it thinks they are redundant, eg.

x = 1;
bExit = true;
x = 2;

can optimize away x = 1;

like image 96
StenSoft Avatar answered Sep 22 '22 01:09

StenSoft