Search code examples
javamultithreadingvolatile

When I use volatile in project, why the code below shows different result?


first:

public class VolatileTest{
    public volatile int inc = 0;
    public void increase(){
        inc++;
    }

    public static void main(String[] args) {
        VolatileTest test = new VolatileTest();
        for(int i = 0 ; i < 2 ; i ++){
            new Thread(){
                public void run(){
                    for(int j = 0 ; j < 1000 ; j++)
                        test.increase();
                }
            }.start();
        } 
        while(Thread.activeCount() > 1)Thread.yield();
        System.out.println(test.inc);
    }
}

second:

public class VolatileTest{
    public volatile int inc = 0;
    public void increase(){
        inc++;
    }

    public static void main(String[] args) {
        VolatileTest test = new VolatileTest();
        new Thread(){
            public void run(){
                for(int j = 0 ; j < 1000 ; j++)
                    test.increase();
            }
        }.start();
        new Thread(){
            public void run(){
                for(int j = 0 ; j < 1000 ; j++)
                    test.increase();
            }
        }.start();
        while(Thread.activeCount() > 1)Thread.yield();
        System.out.println(test.inc);
    }
}

The first one uses a for and the second one doesn't, and that is the only difference, but the first one gets the result smaller than 2000, the second gets the result equals to 2000, why?


Solution

  • That’s just coincidence. Both variants are equally broken, but the second defines two distinct classes doing the same thing, so before starting the second thread, this additional class has to be loaded, verified and initialized. This overhead gives the first thread a headstart, raising the chance of completing entirely before the second even starts.

    So the race condition does not materialize then, but since this execution is not guaranteed, it’s still a broken program containing the possibility of data races. Running the same program in an environment with faster class loading/initialization or an ahead-of-time strategy may exhibit the same behavior as with the first variant.

    Note that likewise, it’s not guaranteed that the first variant will experience lost updates. It may still happen that starting the second thread is slow enough to allow the first one to complete without data races. Even if both threads run, the system’s thread scheduling policy may change the likelihood of experiencing lost updates. Also, the entire loop could get optimized to a single increment by 1000, that would not contradict the requirements for volatile variables, even if the current version of the HotSpot JVM doesn’t do that.