semantic of local final variable in the Java Memory Model?

concurrency, final, java

Solution

I am addressing one point Gray didn't, but I would accept his, as his answer is spot on

The following code sometimes prints "valueWrapper.isZero()" on my Windows-PC and a Mac, both running their JVM in server mode.... It looks like that now no thread sees a stale value of 0. But is this guaranteed by the JMM? A brief look in the spec doesn't convinced me.

The reason you are seeing `valueWrapper.isZero()` returning true sometimes because `valueWrapper` is changing after the `start` is invoked and before `run` gets to the boolean test. If you only have one instance created it will always not be zero as Gray mentioned.

The reason `final ValueWrapper valueWrapper = new ValueWrapper(randomInt(10, 1024));` works all the time is because the field is thread (and method) local and the semantics for a local object and anonymous inner classes is to copy the original reference into the class instance.

Problem

The following code sometimes prints "valueWrapper.isZero()" on my Windows-PC and a Mac, both running their JVM in server mode. Ok this happens because the value field isn't final in the ValueWrapper class, so its possible that some thread sees the stale value 0. ``` public class ConcurrencyApp { private final Random rand = new Random(System.currentTimeMillis()); private ValueWrapper valueWrapper; private static class ValueWrapper { private int value; public ValueWrapper(int value) { this.value = value; } public boolean isZero() { return value == 0; } } private void go() { while (true) { valueWrapper = new ValueWrapper(randomInt(10, 1024)); Thread thread = new Thread(new Runnable() { @Override public void run() { if (valueWrapper.isZero()) { System.out.println("valueWrapper.isZero()"); } } }); thread.start(); } } private int randomInt(int min, int max) { int randomNum = rand.nextInt((max - min) + 1) + min; return randomNum; } public static void printVMInfos() { String vmName = System.getProperty("java.vm.name"); System.out.println("vm name: " + vmName); int cores = Runtime.getRuntime().availableProcessors(); System.out.println("available cores: " + cores); } public static void main(String[] args) { ConcurrencyApp app = new ConcurrencyApp(); printVMInfos(); app.go(); } } ``` But what about the following modification, here i used a local final variable: ``` private void go() { while (true) { final ValueWrapper valueWrapper = new ValueWrapper(randomInt(10, 1024)); Thread thread = new Thread(new Runnable() { @Override public void run() { if (valueWrapper.isZero()) { System.out.println("valueWrapper.isZero()"); } } }); thread.start(); } } ``` It looks like that now no thread sees a stale value of 0. But is this guaranteed by the JMM? A brief look in the spec doesn't convinced me.

Original source

Related problems