Some Java trivia:
In most cases, it is sufficient to simply mark a lazy initialising method as synchronized. The following example can be found in the Wikipedia article about double-checked locking:
// Correct but possibly expensive multithreaded version class Foo { private Helper helper = null; public synchronized Helper getHelper() { if (helper == null) { helper = new Helper(); } return helper; } // other functions and members... }
Sometimes, however, you want to avoid obtaining a lock on the Foo instance every time you access Foo’s Helper. Then you may choose to apply double-checked locking (only with Java 1.5+. A good article why it didn’t work prior to Java 1.5 can be found here). If you forget how it works, or doubt whether it works at all, consider looking at the source code of java.io.File.toPath():
// "volatile" is of the essence, here: private volatile Path filePath; public Path toPath() { Path result = filePath; if (result == null) { synchronized (this) { result = filePath; if (result == null) { result = FileSystems.getDefault().getPath(path); filePath = result; } } } return result; }
Nice trick, I learnt something.