No - your code doesn't work, because the lock object is a local variable and therefore different for every thread.
You are attempting to implement the lazy initialization pattern - where the instance is created when first used.
But there is a simple trick that allows you to code a thread-safe implementation that doesn't require synchronization! It is known as the Initialization-on-demand holder idiom, and it looks like this:
public class Singleton {
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
private Singleton() {
}
// rest of class omitted
}
This code initializes the instance on the first calling of getInstance()
, and importantly dosen't need synchronization because of the contract of the class loader:
- the class loader loads classes when they are first accessed (in this case
Holder
's only access is within the getInstance()` method)
- when a class is loaded, and before anyone can use it, all static initializers are guaranteed to be executed (that's when
Holder
's static block fires)
- the class loader has its own synchronization built right in that make the above two points guaranteed to be threadsafe
It's a neat little trick that I use whenever I need lazy initialization. You also get the bonus of a final
instance, even thought it's created lazily. Also note how clean and simple the code is.