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();
}
}
}