The Singleton pattern ensures that a class has only one instance, and that sole instance is shared among all objects those want to use it.
This pattern can be used when we need guarantee only one instance exists from an object.
A Singleton class can not be instantiated directly because its constructor is private.
The class has a private static field, which holds the reference to the only instance of the class.
To get a reference to it, we need to call a method, usually it's called getInstance
.
This method gives back the same object every time from a static field.
Remember, in Java, static variables cannot be elected for garbage collection while the class is loaded,
therefore the same instance stays alive.
Singleton implementation is very easy. It stands only from one class, but can be implemented in different ways. Below there are three different versions.
Note: With multiple class loaders the Singleton pattern can be broken and results in multiple instances.
Singleton is a creational pattern.
In the lazily created version, the instantiation happens when the getInstance
method get called at the first time. It checks whether the instance
is null
.
At the first call it is, so a new instance is created and returned.
At every further call, the instance
won’t be null
, and just gets returned.
This is the basic logic for the Singleton pattern in Java.
Having an empty object without any benefit is not very useful.
To make sense for its existing, let’s add a collection to it that stores some invaluable data.
In this example, that would be a set of fruits
.
With the Singleton pattern, we can ensure there is one instance of this data exists.
If a client does any modification on it, another client will get reference to the modified one.
package com.programcodex.designpatterns.singleton;
import java.util.HashSet;
import java.util.Set;
public class SingletonLazilyCreated {
private static SingletonLazilyCreated instance;
private Set<String> fruits;
private SingletonLazilyCreated() {
fruits = new HashSet<>();
fruits.add("orange");
fruits.add("apple");
fruits.add("grape");
}
/**
* It's not synchronized, Hopefully it won't cause any problem.
*/
public static SingletonLazilyCreated getInstance() {
if (instance == null) {
instance = new SingletonLazilyCreated();
}
return instance;
}
public Set<String> getFruits() {
return fruits;
}
@Override
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
However, there is a design flaw in above implementation. It’s not thread safe.
What if the instantiation takes a longer time. For example, data collection needed from a slow database.
Meanwhile the data creation happens, another thread will find the instance
as null
,
so it will also create a new object. The solution is in the next example.
In the synchronized version, the getInstance
method has a different implementation.
To ensure that only one thread could create a new instance, we have to use synchronization.
If we made the getInstance
method synchronized
, that would make
the threads waiting each other when multiple calls happen at the same time.
However, synchronization needed only at the first call, not anymore,
so it wouldn't be a good idea to make the whole method synchronized.
That’s why if the instance
is null
, then a synchronized
block is executed. In this block, the instance
checked against null
again,
and if it is still true, the new instance is created.
But why have to check the instance
twice?
Meanwhile the synchronized
block is executed, a second thread could call
the getInstance
method.
It will also find the instance
as null
and try to enter
the synchronized
block, but it has to wait for the first thread to finish with it.
So when the first thread done, the instance
already has a value.
The second thread enters into the synchronized
block,
but if
check won’t be true by this time, therefore the instantiation skipped.
Any further call to this method won’t be concerned by the synchronization.
Finally, notice the volatile
keyword at the instance
field.
It guarantees visibility of changes to variables across multiple threads.
package com.programcodex.designpatterns.singleton;
import java.util.HashSet;
import java.util.Set;
public class SingletonSync {
/**
* The volatile guarantees visibility of changes to variables
* across multiple threads.
*/
private volatile static SingletonSync instance;
private final Set<String> fruits;
private SingletonSync() {
fruits = new HashSet<>();
fruits.add("orange");
fruits.add("apple");
fruits.add("grape");
}
/**
* If the method would be synchronized
* then it would slow down threads unnecessarily
* because synchronization needed only at the beginning.
*/
public static SingletonSync getInstance() {
if (instance == null) {
synchronized (SingletonSync.class) {
if (instance == null) {
instance = new SingletonSync();
}
}
}
return instance;
}
public Set<String> getFruits() {
return fruits;
}
@Override
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
In the eagerly created version the instance gets its value at declaration.
So the getInstance
method got simpler because no needed for synchronization nor null
check.
The static
field gets its value only once when the class is invoked.
It seams to be a bright solution, but be aware of that in this version the instantiation happens every time
the class is used regardless the instance
is used or not.
This should not cause a problem in a well designed software.
It would be a design flaw, if the singleton class were needed, but not needed its instance
variable.
See this in the TestSingleton
class below.
package com.programcodex.designpatterns.singleton;
import java.util.HashSet;
import java.util.Set;
public class SingletonEagerlyCreated {
/**
* This way neither synchronization nor null check
* needed in the getInstance method.
*/
private static final SingletonEagerlyCreated instance =
new SingletonEagerlyCreated();
private final Set<String> fruits;
public static String DESIGN_FLAW =
"This should not be here or at least should be final.";
private SingletonEagerlyCreated() {
fruits = new HashSet<>();
fruits.add("orange");
fruits.add("apple");
fruits.add("grape");
System.out.println("SingletonEagerlyCreated() constructor is called...");
}
public static SingletonEagerlyCreated getInstance() {
return instance;
}
public Set<String> getFruits() {
return fruits;
}
@Override
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
And we are done. It’s time to run these things.
package com.programcodex.designpatterns.singleton;
import java.util.Set;
public class TestSingleton {
public static void main(String[] args) {
System.out.println("Lazily created singleton:\n");
SingletonLazilyCreated stonLazily = SingletonLazilyCreated.getInstance();
print(stonLazily.getFruits());
System.out.println("Synchronized singleton:\n");
SingletonSync stonSync = SingletonSync.getInstance();
Set<String> fruits = stonSync.getFruits();
print(fruits);
System.out.println("Let's add two fruits to the collection, and remove the apple.");
fruits.add("raspberry");
fruits.add("strawberry");
fruits.remove("apple");
System.out.println("Get another instance.");
System.out.println("Whether it contains the modification? Yes, it does:\n");
stonSync = SingletonSync.getInstance();
print(stonSync.getFruits());
System.out.println("Eagerly created singleton:\n");
System.out.println("We don't call the getInstance() method,\n"
+ "but the class is instantiated because a variable is used from the class:");
System.out.println(SingletonEagerlyCreated.DESIGN_FLAW);
}
private static void print(Set<String> set) {
set.stream().forEach(System.out::println);
System.out.println();
}
}
The output of the above test class: