Question

Typical lazy singleton:

public class Singleton {
    private static Singleton INSTANCE;

    private Singleton() {

    }

    public static synchronized Singleton getInstace() {
        if(INSTANCE == null)
            INSTANCE = new Singleton();

        return INSTANCE;
    }
}

Typical eager singleton:

public class Singleton {
    private static Singleton INSTANCE = new Singleton();

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

Why are we not concerned about synchronization with eager singletons, but have to worry about synchronization with their lazy cousins?

Was it helpful?

Solution 2

Since an eager singleton is initialized when the class if first loaded into memory (jit) and this happens only once. However if two clients will try to call the singleton instance method from two threads at the same time, two singletons may be created.

OTHER TIPS

Eager instantiation does not require explicit synchronisation for sharing the reference of the field because the JVM will have handled it for us already as part of the class loading mechanism.

To elaborate in more detail, before a class becomes available to any thread for use, it will have been loaded, verified and initialised. The compiler rewrites the static field assignment into this initialisation stage and via the rules of the Java Memory Model and the underlying hardware architecture will ensure that all threads who access that class will see this version of the class. This means that the JVM will have handled any hardware barriers etc for us.

That said, I would recommend marking the eager initialisation final. This will make your intent clearer and the compiler will enforce that the eager initialisation never changes. If it did, then concurrency control would be required again.

private static **final** Singleton INSTANCE = new Singleton();

FYI If you are interested, section 5.5 of the Java Virtual Machine Specification covers this in much more detail. A couple of choice snippets from the spec are

*"Because the Java Virtual Machine is multithreaded, 
initialization of a class or interface requires careful 
synchronization"*

*"For each class or interface C, there is a unique initialization lock LC"*

*9&10) "Next, execute the class or interface initialization method of C"
"If the execution of the class or interface initialization 
method completes normally, then acquire LC, label the Class object for 
C as fully initialized, notify all waiting threads, release LC, and 
complete this procedure normally."*

It is in step 10 of the spec where the static fields will have been set, and the use of a lock (LC) is used to ensure that only one thread performs the initialisation and that the result is shared correctly.

Because in the latter example the instance of the Singleton is always present when the getInstance is called - nothing to synchronize here. That is in contrary to the first example where the instance isn't necessary initialized yet. In this case the getInstance contains critical section (the if and it's body) which needs to be protected (e.g. by synchronization) against simultaneous access.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top