I'm trying to implement a reusable functional-like version of the double checked lock (DCL) pattern in Java.
Indeed, there are many known problems with the DCL pattern in Java, like those ones. So I'm trying to check if the solution I develop has any flaws.
Here is the DCL executor code:
public class DoubleCheckedLockExecutor {
public <T> T getOrCreate(Supplier<T> supplier, Supplier<T> builder, Consumer<T> consumer, Predicate<T> build) {
if (build.test(supplier.get())) {
synchronized (this) {
if (build.test(supplier.get())) {
consumer.accept(builder.get());
}
}
}
return supplier.get();
}
}
And here a Singleton class that uses it:
public class Singleton {
private static Singleton instance = null;
private static final AtomicInteger instanceCount = new AtomicInteger();
private static final DoubleCheckedLockExecutor dclExec = new DoubleCheckedLockExecutor();
private Singleton() {
instanceCount.incrementAndGet();
}
public static Singleton getInstance() {
return dclExec.getOrCreate(() -> instance, Singleton::new, s -> instance = s, s -> s == null);
}
public static int getInstanceCount() {
return instanceCount.get();
}
}
And finally some test code:
@Test
public final void testGetOrCreate() {
int calls = 1000;
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
try {
for (int i = 0; i < calls; i++) {
executor.execute(() -> Singleton.getInstance());
}
} catch (Exception e) {
e.printStackTrace();
}
executor.shutdown();
while (!executor.isTerminated()) {
}
assertEquals(1, Singleton.getInstanceCount());
}
All tests and analysis I did showed no problems (duplicated instances, for example). But multi-thread and concurrency test is not such easy task for me. So could you guys help me out with this? Could I say this implementation is thread safe and produce the expected results?