Singleton Pattern Examples and Implementation
Implementation of Singleton
Design pattern
To implement a singleton pattern, we have different
approaches, but all of them have the following common concepts.
--Private constructor to restrict instantiation of the
class from other classes.
--Private static variable of the same class that is the
only instance of the class.
--Public static method that returns the instance of the
class, this is the global access point for the outer world to get the instance
of the singleton class.
Let’s put them in Action.
Approach-1
In eager initialization, the
instance of the singleton class is created at the time of class loading. The
drawback to eager initialization is that the method is created even though the
client application might not be using it. Here is the implementation of the
static initialization singleton class
public class EagerInitializedSingleton {
private static final EagerInitializedSingleton instance =
new EagerInitializedSingleton();
// private constructor to avoid client
applications using the constructor
private EagerInitializedSingleton(){}
public static EagerInitializedSingleton
getInstance() {
return instance;
}
}
If your singleton class is not using a lot of resources,
this is the approach to use. But in most of the scenarios, singleton classes
are created for resources such as File System, Database connections, etc. We
should avoid the instantiation unless the client calls
the getInstance method. Also, this method doesn’t provide any options
for exception handling.
Approach-2
Static Block Initialization
Static block initialization implementation is similar
to eager initialization, except that instance of the class is created in the
static block that provides the option for exception handling.
public class StaticBlockSingleton {
private static StaticBlockSingleton instance;
private StaticBlockSingleton(){}
// static block initialization for exception handling
static {
try {
instance = new StaticBlockSingleton();
} catch (Exception e) {
throw new RuntimeException("Exception occurred in
creating singleton instance");
}
}
public static StaticBlockSingleton getInstance() {
return instance;
}
}
Both eager initialization and static block initialization
create the instance even before it’s being used and that is not the best
practice to use.
Approach-3
Lazy Initialization
Lazy initialization method to implement the singleton
pattern creates the instance in the global access method. Here is the sample
code for creating the singleton class with this approach:
public class LazyInitializedSingleton {
private static LazyInitializedSingleton
instance;
private LazyInitializedSingleton(){}
public static LazyInitializedSingleton
getInstance() {
if (instance == null) {
instance = new
LazyInitializedSingleton();
}
return instance;
}
}
The preceding implementation works fine in the case of the
single-threaded environment, but when it comes to multi-threaded systems, it
can cause issues if multiple threads are inside the if condition at the same
time. It will destroy the singleton pattern and both threads will get different
instances of the singleton class.
Approach-4
Thread-safe Singleton
A simple way to create a thread-safe singleton class is to
make the global access method synchronized so that only one thread can
execute this method at a time. Here is a general implementation
of this approach:
public class ThreadSafeSingleton {
private static
ThreadSafeSingleton instance;
private
ThreadSafeSingleton(){}
public static
synchronized ThreadSafeSingleton getInstance() {
if
(instance == null) {
instance
= new ThreadSafeSingleton();
}
return
instance;
}
The preceding implementation works fine and
provides thread-safety, but it reduces the performance because of the cost
associated with the synchronized method, although we need it only for the first
few threads that might create separate instances. To avoid this extra overhead
every time, double-checked locking principle is used. In this
approach, the synchronized block is used inside the if condition with
an additional check to ensure that only one instance of a singleton class is
created. The following code snippet provides the double-checked locking
implementation:
public static ThreadSafeSingleton
getInstanceUsingDoubleLocking() {
if (instance == null) {
synchronized
(ThreadSafeSingleton.class) {
if
(instance == null) {
instance
= new ThreadSafeSingleton();
}
}
}
return instance;
}
How Singleton Pattern Break?
·
One of the easiest way
one can break singleton pattern is via Reflection API, Reflection API has the
power to modify the behaviour of methods, classes, and interfaces at runtime.
·
One can say one can
get the blueprint of class via Reflection API. So, the basic idea to break
Singleton Design pattern via Reflection is one can get access to the private
constructor of class make it public runtime and can create another instance of
it.
How to overcome it?
· We can use Enum to overcome it as whenever we declare enum those will be static values by default, so we can directly call them.
· Another thing is whatever the constructors are called we as developer cannot call constructor JVM itself calls it so we are safe there as well...!!
· And it’s also thread Safe.
Example to break Singleton Pattern via Reflection.
class
Singleton {
// public instance initialized when loading the class
public static Singleton instance = new Singleton();
private Singleton()
{
// private constructor
}
}
public
class BreakSingleton {
public static void main(String[] args)
{
Singleton instance1 = Singleton.instance;
Singleton instance2 = null;
try {
Constructor[] constructors
= Singleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// Below code will destroy the singleton
// pattern
constructor.setAccessible(true);
instance2
= (Singleton)constructor.newInstance();
break;
}
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("instance1.hashCode():- "
+ instance1.hashCode());
System.out.println("instance2.hashCode():- "
+ instance2.hashCode());
}
}
public enum SingletonSafe {
INSTANCE;
public void getInformation() {
System.out.println("Hello World");
}
}
public class SingletonPattern {
public static void main(String[] args) {
SingletonSafe.INSTANCE.getInformation();
}
Comments
Post a Comment