3

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?

5
  • 1
    Because there is no possible race condition? Commented Mar 2, 2013 at 19:21
  • 2
    @OliCharlesworth - But lazy singletons don't race, they just amble along. Commented Mar 2, 2013 at 19:21
  • Thanks @OliCharlesworth (+1) - can you explain with a more in-depth answer? Commented Mar 2, 2013 at 19:22
  • @HotLicks the instantiation and the check create an inherent race Commented Mar 2, 2013 at 19:28
  • @icepack - I guess you didn't see the implied ;). Commented Mar 3, 2013 at 1:00

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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.

10 Comments

How do two singletons get created??
If not synchronized, both threads may reach the is null check, see that it is true and create a new instance
How can a static have more than one value?
It wont have 2 values. but it may still call new() twice and might even return 2 different objects to the 2 clients. there is a lot of information on that issue. if you want i will give you more info and links
worth noting that double lock problematics are mostly inherent to the Java language, not to the concept itself
|
0

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.

5 Comments

Although this raises an interesting point (at least, in my head!); what happens if the static initializer in another class decides to call Singleton.getInstance()?
@OliCharlesworth that's why the synchronized keyword is present in the getInstance signature
I mean in the eager version. (My question is really nothing to do with concurrency; I just realised I didn't know how Java defined the relative order of static initializations of different classes.)
@OliCharlesworth Ah, misunderstood you. I believe that's implicitly answered in the omerschleifer answer - JIT probably takes care of consistency here (though my knowledge of Java is limited, maybe someone more knowledgeable can answer)
Static initialization of a class is inherently synchronized by the JVM. Anything in the static init method of the class will be executed only once, and before the class is made "visible".

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.