Thursday, September 27, 2012

java's double checked idiom


Ever since Josh Bloch's Effective Java book everyone has constantly been bring up Java memory model as something that doesn't work when trying to do double check. Example:

  public Helper getHelper() {
    if (helper == null) {
      synchronized(this) {
        if (helper == null) {
          helper = new Helper();
        }
      }
    }


There are lot's of entries saying that this test will only work if you use "volatile" when defining helper in the above example. Well I decided to try and get the concurrent error to actually occur. It appears that with Java 6 that this problem doesn't exist and that the double idiom check really does work. Here is my code example:



import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class ConcurrencyTest {
static class Lock {
private AtomicInteger ai = new AtomicInteger(0);
private Integer mutex;

public void reset() {
ai = new AtomicInteger(0);
mutex = null;
}

public Integer getMutex() {
if (mutex == null) {
synchronized (this) {
if (mutex == null) {
mutex = ai.getAndIncrement();
}
}
}
return mutex;
}

}

public static void main(String[] args) {
final AtomicInteger counter = new AtomicInteger(1);

final Lock key = new Lock();
final CyclicBarrier barrier = new CyclicBarrier(8, new Runnable() {

@Override
public void run() {
key.reset();
if (counter.getAndIncrement() % 10000 == 0) {
System.out.println("Reset Lock");
}
}
});

Thread[] threads = new Thread[8];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
barrier.await();
Integer i = key.getMutex();
if (i != 0) throw new IllegalStateException("Value was: " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}

for (Thread thread : threads) {
thread.start();
}

}
}