Your biggest flaw is synchronizing on every getSingleton()
call.
The idea of "double checked" locking is to first perform an unsynchronized check. This is for cases where the singleton is already initialized. If the singleton already exists, there is no reason to synchronize
If the singleton is null
when you perform the unsynchronized check, you THEN synchronize:
public Singleton getSingleton() {
if(singleton == null) {
synchronized(lock) {
}
}
}
Now we need to make sure no other threads may have initialized the singleton from the time we leave the null check to the time we enter the synchronized block. If the singleton has been created in that time, we don't want to create a new singleton. That's why we perform a second null-check:
public Singleton getSingleton() {
if(singleton == null) {
synchronized(lock) {
if(singleton == null) {
//create
}
}
}
}
An easier way to avoid this would to use the Initialize-On-Demand idiom:
class Singleton {
private static final Singleton SINGLETON = new Singleton();
public static Singleton getSingleton() {
return SINGLETON;
}
}
The idea is to let the mechanism that handles static initialization (which is already synchronized) to handle the creation for you.
An even easier alternative would be an enum
:
public enum Singleton {
INSTANCE;
}
To reduce verbosity, I usually use GET
instead of INSTANCE
. That's assuming you aren't using static imports, which you should be using a more suitable name if that were the case.