The Singleton Pattern
Singleton pattern is a design solution where you can:
- ensure that only one instance of a class is created;
- provide a global point of access to the object;
- allow multiple instances in the future without affecting a singleton class’s clients.
Lazy initialization
In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed.
EagerSingleton.java
public class EagerSingleton {
private static volatile EagerSingleton instance = null;
public static EagerSingleton getInstance() {
if (instance == null) {
synchronized (EagerSingleton.class) {
if (instance == null) {
instance = new EagerSingleton();
}
}
}
return instance;
}
// private constructor prevents instantiation from other classes
private EagerSingleton() {}
}
This method uses double-checked locking, which should not be used prior to J2SE 5.0 as it is vulnerable to subtle bugs.
Eager initialization
If the program will always need an instance, or if the cost of creating the instance is not too large in terms of time/resources, the programmer can switch to eager initialization, which always creates an instance.
EagerSingleton.java
public class EagerSingleton {
private static volatile EagerSingleton instance = new EagerSingleton();
public static EagerSingleton getInstance() {
return instance;
}
// private constructor prevents instantiation from other classes
private EagerSingleton() {}
}
This method has a number of advantages:
- the instance is not constructed until the class is used;
- there is no need to synchronize the getInstance() method, meaning all threads will see the same instance and no (expensive) locking is required;
- the
final
keyword means that the instance cannot be redefined, ensuring that one (and only one) instance ever exists.
Static block initialization
The static blocks are executed during the loading of class and even before the constructor is called so the programmer can use this feature in the singleton pattern.
StaticBlockSingleton.java
public class StaticBlockSingleton {
private static final StaticBlockSingleton INSTANCE;
static {
try {
INSTANCE = new StaticBlockSingleton();
} catch (Exception e) {
throw new RuntimeException("Unexpected exception!!!...", e);
}
}
public static StaticBlockSingleton getInstance() {
return INSTANCE;
}
// private constructor prevents instantiation from other classes
private StaticBlockSingleton() {}
}
This method has one drawback. Suppose there are 5 static fields in class and application code needs to access only 2 or 3, for which instance creation is not required at all. So, if we use this static initialization, we will have one instance created though we require it or not.
Bill Pugh solution
Bill Pugh was main force behind java memory model changes. His principle (initialization-on-demand holder idiom) also uses static block but in different way. It suggest to use static inner class.
BillPughSingleton.java
public class BillPughSingleton {
private static class LazyHolder {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return LazyHolder.INSTANCE;
}
// private constructor prevents instantiation from other classes
private BillPughSingleton() {}
}
The LazyHolder
is loaded on the first execution of BillPughSingleton.getInstance()
or the first access to LazyHolder.INSTANCE
, not before.
Using Enum
This type of implementation recommend the use of enum
. Enum, as written in java docs, provide implicit support for thread safety and only one instance is guaranteed. This is also a good way to have singleton with minimum effort.
EnumSingleton.java
public enum EnumSingleton {
INSTANCE;
public void doSomething(String param) {
// perform operation here
}
}
The public method can be written to take any desired types of arguments; a single String
argument is used here as an example.
This approach implements the singleton by taking advantage of Java’s guarantee that any enum
value is instantiated only once in a Java program. Since Java enum values are globally accessible, so is the singleton, initialized lazily by the classloader. The drawback is that the enum
type is somewhat inflexible.
Resources
- Lazy initialization - Wikipedia
- Double-checked locking - Wikipedia
- Java Memory Model - Wikipedia
- Initialization-on-demand holder idiom - Wikipedia
- http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html
Categories & Tags
Share