javamultithreadingjitnon-volatile

Is JIT reason of this behaviour?


Inspired by this question, I wrote the test:

public class Main {

    private static final long TEST_NUMBERS = 5L;

    private static final long ITERATION_NUMBER = 100000L;

    private static long value;

    public static void main(final String [] args) throws Throwable {
        for(int i=0; i<TEST_NUMBERS; i++) {
            value = 0;
            final Thread incrementor = new Thread(new Incrementor());
            final Thread checker = new Thread(new Checker());
            incrementer.start();
            checker.start();
            checker.join();
            incrementer.join();
        }
    }

    static class Incrementor implements Runnable {
        public void run() {
            for(int i=0; i<ITERATION_NUMBER; i++){
                ++value;
            }
        }
    }

    static class Checker implements Runnable {
        public void run() {
            long nonEqualsCount = 0;
            for(int i=0; i<ITERATION_NUMBER; i++){
                if(value != value) {
                    ++nonEqualsCount;
                }
            }
            System.out.println("nonEqualsCount = " + nonEqualsCount);
        }
    }
}

This program are printed in common case:

nonEqualsCount = 12; //or other non 0 value;
nonEqualsCount = 0;
nonEqualsCount = 0;
nonEqualsCount = 0;
nonEqualsCount = 0;

First: I explain this behaviour is presence of the JIT-compiler. JIT-compiler cache value non volatile field for each thread after "warmup". It right?

Second: If first right or not right, how can I verify this?

P.S. - I know about PrintAssebly-option.

Update: enviroment: Windows 7 64bit, JDK 1.7.0_40-b43(Hot Spot).


Solution

  • What you see is probably an artifact of the JIT. Before it kicks in, the Java byte code is interpreted which means there are a lot of chances for the checker thread to get interrupted during the comparison.

    Also, since more code is executed, there is a higher chance that the CPU caches will need flushing.

    When the code is optimized by the JIT, it will probably insert 64bit operations and since only small amounts of code are being executed, the caches won't be flushed to main memory anymore which means that the threads have no chance to see the changes made by the other one.