Reputation: 741
I done example program to understand how volatile work. In the below example Even without volatile the program work fine. Could some one help me to understand how the program works fine without volatile?
public class VolatileExp {
private /*volatile*/ boolean statusFlag=false;
private void changeState() {
try {
int counter=0;
while (!statusFlag) {
System.err.println("counter: "+counter++);
//Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
final VolatileExp hello = new VolatileExp();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
hello.changeState();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
hello.statusFlag=true;
System.err.println("setting the status flag ");
} catch (Exception e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
Upvotes: 3
Views: 135
Reputation: 298103
There are several reasons why you can’t observe missing updates for your non-volatile
variable.
As pointed out by others in the comments, you can’t rely on failures to happen. In this very example, your program runs too short, so the optimizer won’t make any effort here. Running your program with the -server
option will change that.
Further, you are executing a System.err.println(…);
statement within the loop which is internally synchronized
. Hence, the heap variables will be re-read in every iteration unless the optimizer decides to enlarge the synchronized
code block to cover the entire loop (which is rather unlikely as this would imply holding a lock forever). So after the heap value changed, sooner or later, the first thread will eventually read the changed flag.
Since the second thread also invokes System.err.println(…);
after changing the flag it will be forced to actually write the updated values to the heap so both threads are implicitly synchronized
on System.err
. But even without doing the printout the second thread will eventually write the value to the heap as the thread ends afterwards.
So you have a program that works on most systems due to side-effects but is still broken. Note that in theory the first thread running in a loop consuming 100% CPU time could force the second thread to never run and thus never set the termination flag. However, most today’s systems will preemptively switch between threads.
Even if it worked every time, relying on it was very dangerous as it is not easy to see the side-effects on which it relies which means, simple changes like removing the print statement in the first thread and running with the -server
option (or on any other JVM performing similar optimizations) would turn the program from accidentally running into likely breaking.
Upvotes: 4