Amazon Interview Question
Country: India
Synchronizing only the part where the instance is created is not by itself considered double-checked locking. There has to be a double check. Specifically, the pattern is something like
if (instance == null) {
lock (this) {
//if still null after lock has been acquired
if (instance == null) {
instance = new MySingleton ();
}
}
}
Though seemingly clever, this pattern actually has well-known problems in many cases and is often considered an anti-pattern. See the Wikipedia article on "double-checked locking".
DCL alone cannot solve the problem completely. In Java, you ought to combine the usage of 'volatile' keyword with Double Checked Locking, why because 'volatile' ensures memory visibility across all the threads when updates to a variable are made.
In the above post, 'instance' has to be declared volatile, so when another thread has set its value, the 'if (instance == null)' check in the code below works correctly in the current thread.
//if still null after lock has been acquired
if (instance == null) {
instance = new MySingleton ();
}
Not sure how to get the DCL anti-pattern work correctly in other languages.
@Dumbo Good point. Though the known problems with DCL are not due to the double checked locking pattern, but due to the programming language used to implement the pattern. For example, for non static singleton instance version, like you've suggested, Java fixed this issue by using volatile for the singleton instance (Also note that this is Java 5 and up). You don't have to use volatile instance, for instance for the static version, a final static wrapper object, can also be used in Java.
your answer is correct, but double checking lock won't solve problem completely. There was a problem due to java memory model, that is it allows out of order writes. Using volatile everything will be solved, since its atomic varible.
Don't ever try "double checked locking". It has been debated and proven in the past 10 years to be bad approach.
This can be done by Double locking with synchronized block:
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class)
{
if (instance == null)
{
System.out.println("getInstance(): First time getInstance was invoked!");
instance = new Singleton();
}
}
}
return instance;
}
Problem: You have to synchronize the getInstance() method, because there is a possibility that while one thread is creating the singleton instance for the first time (this is point just before the new() is called to created the instance), the other one might be also executing the getInstance() method and checking if the instance is already created. Since the instance is not created yet by thread one, the second thread will see that the instance is null and try to create it again.
- oOZz July 02, 2013Solution: You can either synchronize the getInstance() method, which will be expensive. So, there is a better approach called "double checked locking", where you only synchronize the part where the instance is created. This is less expensive than synchronizing the whole method, but you check the instance again for nullness in the syncronized block before creating it.