james007
james007

Reputation: 741

Making Java Volatile to work

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

Answers (1)

Holger
Holger

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

Related Questions