I just faced problem with synchronization many threads starting at the same time (with microseconds difference) and creating single object instance of connection to the database using a Singleton Pattern in Java. As a result I had many connections except one. The sent queries counter has been set to smaller value as excepted in simulations.
I have just Google’d the IBM article by Peter Haggar, Senior Software Engineer „Double-checked locking and the Singleton pattern”.
Problem overview
Creating an singleton in Java is simple to implement. There are two common ways to create singleton:
- Lazy loaded with create an
private static
field_instance
filled bynull
(by default Java object initialization). The instance is created, when thestatic
methodgetInstance()
is called. - Create an class instance in advance, just before class is loaded to memory by declaring a value of
priate static
field_instance
by calling theprivate
constructornew SingletonClass();
1st implementation with lazy initialization
package pl.athlan.examples.singleton;
public class Singleton {
private static Singleton _instance; // null by default
private Singleton() {
}
public static Singleton getInstance() {
if(_instance == null) {
_instance = new Singleton();
}
return _instance;
}
}
2nd implementation with eager initialization
package pl.athlan.examples.singleton;
public class Singleton {
private static Singleton _instance = new Singleton(); // object is created just after class is loaded into memory
private Singleton() {
}
public static Singleton getInstance() {
return _instance;
}
}
Motivation.
Imagine two separated threads with is delegated to call getInstance() method at the same time.
Thread #1 | Thread #2 | value of _instance |
---|---|---|
Singleton.getInstance() |
null |
|
Singleton.getInstance() |
null |
|
if(_instance == null) |
null |
|
if(_instance == null) |
null |
|
_instance = new Singleton() |
[object #1] |
|
_instance = new Singleton() |
[object #2] |
As a result, two object has been created, because thread #2 hasn’t noticed the object creation.
If your object stores common data like a (in my case) database queries counter or the creation of the object is time-expensive when the system just hang out for many threads – this situation have not to occur.
Sloving the problem.
The problem slove is to synchronize the threads while accessing getInstace method. You can simply write:
public static synchronized Singleton getInstance()
but this solution produces an huge overhead to synchronize all threads calling this method. The better solution is to synchronize the fragment of code which checks an existance and creates the object in fact, except of returing if it already exists.
Finally solution:
package pl.athlan.examples.singleton;
public class Singleton {
private volatile static Singleton _instance;
private Singleton() {
}
public static Singleton getInstance() {
if(_instance == null) {
// causes that this block will be processed in sequence in parallel computing mode
synchronized(Singleton.class) {
// if previous sequence created the instance, just omit object creation
if(_instance == null) {
_instance = new Singleton();
}
}
}
return _instance;
}
}
The volatile
keyword assigned to _instance
field provides the synchronization.
If there is no instance of the object, the synchronized block will begin. It means that all processes are queued to access that block. After access just ensure one more time, if the single object is not exists in fact, because the process doesn’t know what happened before it has rached the queue. If any process before queueing has created the object, just ommit the creation.
Hope it helped!
NOTE: Note that implementing Singleton by an ENUM is thread-safe and reflection-safe.