Singleton Design Pattern and 7 Ways to Implement It 4 Ways to Break Singleton Design Pattern

Categories: Java Java Examples Java Design Pattern

Content Image

Singleton Design Pattern and 7 Ways to Implement It 4 Ways to Break Singleton Design Pattern


Singleton solves Problem -In software development, we often require classes that can only have one object for a JVM . For example in thread pools, caches, loggers etc.

What is the Singleton Design Pattern?

Singleton Pattern is a creational design pattern that guarantees a class has only one instance and provides a global point of access to it.Singleton involves only one class which is responsible for instantiating itself, making sure it creates not more than one instance.

Implementation

To implement the singleton pattern, we must prevent external objects from creating instances of the singleton class. Only the singleton class should be permitted to create its own objects.

Additionally, we need to provide a public method for external objects to access the singleton object.

This can be achieved by making the constructor private and providing a public static method for external objects to access it.

The instance class variable holds the one and only instance of the SingletonClassName class.

The SingletonClassName() constructor is declared as private, preventing external objects from creating new instances.

The getInstance() method is a static class method, making it public so that it is accessible to the external world.

There are 7 ways to implement the Singleton Pattern, each with its own advantages and disadvantages.

  1.  Lazy Initialization[ Never used -Break By Multi threaded]

    1-Break :- How to Break Lazy Initialization Singleton?
    2-Break Lazy Initialization using reflection
    3.Check :-How to stop breaking singleton design patterns using reflection?
    4.Break:- how to break singleton design pattern using serializable in java
    5.Check:-How to stop break singleton design pattern using serializable in java
    6.Break Singleton :- How to stop break singleton design pattern using clone in java
    7.Check:-Prevent Singleton Pattern From Cloning
  2. Thread-Safe Singleton
  3. Double-Checked Locking
  4. Eager Initialization
  5. Bill Pugh Singleton
  6. Enum Singleton
  7. Static Block Initialization

1. Lazy Initialization

This approach creates the singleton instance only when it is needed, saving resources if the singleton is never used in the application.

package r4r.co.in.singleton.lazy;

public class LazyInitializationSingleton {

        private static LazyInitializationSingleton INSTANCE;

        private LazyInitializationSingleton() {

                System.out.println("I am in Singleton class....");

        }

        public static LazyInitializationSingleton getInstance() {

                if (INSTANCE == null) {                        

                        INSTANCE = new LazyInitializationSingleton();

                }

                return INSTANCE;

        }

}

  • Checks if an instance already exists (instance == null).
  • If not, it creates a new instance.
  • If an instance already exists, it skips the creation step.

This implementation is not thread-safe. If multiple threads call getInstance() simultaneously when an instance is null, it's possible to create multiple instances.

How to Break Lazy  Initialization Singleton?
Break Lazy Initialization Singleton Using MultiThreading- Here two threads created you can run code and see two time constructors initialized. You know construct initialized by JVM only when a new object is created .Hence proved Singleton break in case of multithreaded aspects.

package r4r.co.in.singleton.lazy;

public class BreakLazyInitializationSingleton {

        public static void main(String[] args) {

                //Break Lazy Initialization Singleton Using MultiThreading

                Thread thread1 = new Thread(() -> {

                        LazyInitializationSingleton singleTonObj1
 = LazyInitializationSingleton.getInstance();

                });

                Thread thread2 = new Thread(() -> {

                        LazyInitializationSingleton singleTonObj2
 = LazyInitializationSingleton.getInstance();

                });

                thread1.start();

                thread2.start();

        }

}
Output:-[Some time]
I am in Singleton class....

I am in Singleton class....

Break Lazy Initialization using reflection  :-
As below example

package r4r.co.in.singleton.lazy.breaksingleton;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

import r4r.co.in.singleton.lazy.LazyInitializationSingleton;

public class BreakLazyInitializationUsingReflaction {

// Break Lazy Initialization using reflection

        @SuppressWarnings("unchecked")

        public static void main(String[] args) throws ClassNotFoundException,
 NoSuchMethodException, SecurityException,

                        InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

                LazyInitializationSingleton instance = LazyInitializationSingleton.getInstance();

                Class<?> singleTonClass = Class.forName("r4r.co.in.singleton.lazy.LazyInitializationSingleton");

                Constructor<LazyInitializationSingleton> constructorOfSingleTon = (Constructor<LazyInitializationSingleton>
) singleTonClass

                                .getDeclaredConstructor();

                constructorOfSingleTon.setAccessible(true);

        //        constructorOfSingleTon.newInstance();

                LazyInitializationSingleton instanceReflection = constructorOfSingleTon.newInstance();

                System.out.println(instanceReflection);

                System.out.println(instance);

        }

}

Output
I am in Singleton class....

I am in Singleton class....

r4r.co.in.singleton.lazy.LazyInitializationSingleton@1936f0f5

r4r.co.in.singleton.lazy.LazyInitializationSingleton@6615435c

How to stop break singleton design pattern using reflection?
Prevent Break SIngleton
 :-Within the private constructor of your singleton class, add a check to see if an instance already exists and throw an exception if it does
.

package r4r.co.in.singleton.lazy;
public
 class LazyInitializationSingleton {

        private static LazyInitializationSingleton INSTANCE;

        private LazyInitializationSingleton() {

                

                  if (INSTANCE != null) {

                    throw new IllegalStateException("Singleton already exists");

                }

                  INSTANCE = this;

                  System.out.println("I am in Singleton class....");

        }

        public static LazyInitializationSingleton getInstance() {

                if (INSTANCE == null) {

                        

                        INSTANCE = new LazyInitializationSingleton();

                }

                return INSTANCE;

        }

}

 

Break:- how to break singleton design pattern using serializable in java
Change in Class
 :- Need to implements Serializable

package r4r.co.in.singleton.lazy;

import java.io.Serializable;

public class LazyInitializationSingleton implements Serializable{

        private static final long serialVersionUID = 1L;

        private static LazyInitializationSingleton INSTANCE;

        private LazyInitializationSingleton() {

        

                  System.out.println("I am in Singleton class....");

        }

        public static LazyInitializationSingleton getInstance() {

                if (INSTANCE == null) {

                        

                        INSTANCE = new LazyInitializationSingleton();

                }

                return INSTANCE;

        }

}



Break:- how to break singleton design pattern using serializable in java

package r4r.co.in.singleton.lazy.breaksingleton;
import
 java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

import r4r.co.in.singleton.lazy.LazyInitializationSingleton;

public class BreakSingletonUsingSerializable  {

        public static void main(String[] args)
 throws  FileNotFoundException
, IOException, ClassNotFoundException
 {

                // Break Singleton Using Serializable

                LazyInitializationSingleton initializationSingleton=
LazyInitializationSingleton
.getInstance();

                

                ObjectOutputStream objectOutputStream=new ObjectOutputStream(new 
FileOutputStream ("d://serializable.ser"))
;

           objectOutputStream.writeObject(initializationSingleton);        

           objectOutputStream.close();

         

           ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream
(
"d://serializable.ser"));

           LazyInitializationSingleton serializableSingleton=(LazyInitializationSingleton) inputStream.readObject();

         

           System.err.println(serializableSingleton.hashCode());

           System.err.println(initializationSingleton.hashCode());

         

        }

}
Output:-
I am in Singleton class....

644166178

1651945012


How to stop break singleton design pattern using serializable in java
To prevent breaking the Singleton pattern when using serialization in Java, you need to implement the readResolve() method in your Singleton class. This method ensures that the same instance is returned after deserialization.
r
eadResolve is an private method used in ObjectInputStream while deserializing an object.

package r4r.co.in.singleton.lazy;

import java.io.Serializable;

public class LazyInitializationSingleton implements Serializable{

        /**

         *

         */

        private static final long serialVersionUID = 1L;

        private static LazyInitializationSingleton INSTANCE;

        private LazyInitializationSingleton() {

        

                  System.out.println("I am in Singleton class....");

        }

        public static LazyInitializationSingleton getInstance() {

                if (INSTANCE == null) {

                        

                        INSTANCE = new LazyInitializationSingleton();

                }

                return INSTANCE;

        }

        

        // Method to handle deserialization

   private Object readResolve() {

       return INSTANCE;

   }

}

Output ➖
I am in Singleton class....

1651945012

1651945012



Break Singleton using clone:- How to stop break singleton design pattern using clone in java

package r4r.co.in.singleton.lazy;

public class LazyInitializationSingleton implements Cloneable {

        private static LazyInitializationSingleton INSTANCE;

        private LazyInitializationSingleton() {

                System.out.println("I am in Singleton class....");

        }

        public static LazyInitializationSingleton getInstance() {

                if (INSTANCE == null) {

                        

                        INSTANCE = new 
LazyInitializationSingleton();

                }

                return INSTANCE;

        }

        

         @Override

        public Object clone()

                throws CloneNotSupportedException

            {

                return super.clone();

            }

}

package r4r.co.in.singleton.lazy.breaksingleton;

import r4r.co.in.singleton.lazy.LazyInitializationSingleton;

public class BreakSingletonUsingClone {

        public static void main(String[] args) throws CloneNotSupportedException
 {

                LazyInitializationSingleton initializationSingleton=LazyInitializationSingleton.getInstance();

                LazyInitializationSingleton clonedSingleton=(LazyInitializationSingleton) initializationSingleton.clone();

                System.err.println(initializationSingleton.hashCode());

                System.err.println(clonedSingleton.hashCode());

                

        }

}



Prevent Singleton Pattern From Cloning:-

Override clone() and throw new CloneNotSupportedException()  or return INSTANCE;  .It will resolve singleton break issue using clone

package r4r.co.in.singleton.lazy;

public class LazyInitializationSingleton implements Cloneable {

        private static LazyInitializationSingleton INSTANCE;

        private LazyInitializationSingleton() {

                System.out.println("I am in Singleton class....");

        }

        public static LazyInitializationSingleton getInstance() {

                if (INSTANCE == null) {

                        

                        INSTANCE = new 
LazyInitializationSingleton();

                }

                return INSTANCE;

        }

        

         @Override

        public Object clone()

                throws CloneNotSupportedException

            {

                      // return INSTANCE;

    throw new CloneNotSupportedException();

            }

}

2. Thread-Safe Singleton

This approach is similar to lazy initialization but also ensures that the singleton is thread-safe.

This is achieved by making the getInstance() method synchronized ensuring only one thread can execute this method at a time.

When a thread enters the synchronized method, it acquires a lock on the class object. Other threads must wait until the method is executed.

package r4r.co.in.singleton.lazy;

public class ThreadSafeLazyInitializationSingleton {

        //Thread-Safe Singleton

        private ThreadSafeLazyInitializationSingleton() {

                System.out.print("I am in Singleton Class");

        }

  private static ThreadSafeLazyInitializationSingleton INSTANCE; 

  public static synchronized ThreadSafeLazyInitializationSingleton getInstance() {

           if(INSTANCE==null) {

                   INSTANCE=new ThreadSafeLazyInitializationSingleton();

           }

           return INSTANCE;

  } 

}

  • The synchronization keyword ensures that only one thread can perform the (instance == null) check and create the object.

If calling the getInstance() method isn’t causing substantial overhead, this approach is straightforward and effective.

But, using synchronized can decrease performance, which can be a bottleneck if called frequently.

3. Double-Checked Locking

This approach minimizes performance overhead from synchronization by only synchronizing when the object is first created.

It uses the volatile keyword to ensure that changes to the instance variable are immediately visible to other threads.

package r4r.co.in.singleton.lazy;

public class DoubleCheckedLocking {

        // Double-Checked Locking

        private DoubleCheckedLocking() {

                System.out.print("Double Checked Locking");

        }

        //The volatile keyword to ensure that changes to the instance variable are immediately visible to other threads.

        private static volatile DoubleCheckedLocking INSTANCE;

        public static  DoubleCheckedLocking getInstance() {

                if (INSTANCE == null)

                        synchronized (DoubleCheckedLocking.class) {

                                if (INSTANCE == null) {

                                        INSTANCE = new DoubleCheckedLocking();

                                }

                        }

                return INSTANCE;

        }

}

  • If the first check (instance == null) passes, we synchronize on the class object.
  • We check the same condition one more time because multiple threads may have passed the first check.
  • The instance is created only if both checks pass.

Although this method is a bit complex to implement, it can drastically reduce the performance overhead.

4. Eager Initialization

In this method, we rely on the JVM to create the singleton instance when the class is loaded. The JVM guarantees that the instance will be created before any thread accesses the instance variable.

This implementation is one of the simplest and inherently thread-safe without needing explicit synchronization.

package r4r.co.in.singleton.eager;

public class EagerInitialization {

        //Eager Initialization -Singleton Example.

        private final static EagerInitialization INSTANCE= new EagerInitialization();

        

        private EagerInitialization() {

                System.out.print("EagerInitialization");

        }

        public static EagerInitialization getInstance() {

                return INSTANCE;

        }        

}

  • static variable ensures there's only one instance shared across all instances of the class.
  • final prevents the instance from being reassigned after initialization.

This approach is suitable if your application always creates and uses the singleton instance, or the overhead of creating it is minimal.

While it is inherently thread-safe, it could potentially waste resources if the singleton instance is never used by the client application.

5. Bill Pugh Singleton

This implementation uses a static inner helper class to hold the singleton instance. The inner class is not loaded into memory until it's referenced for the first time in the getInstance() method.

It is thread-safe without requiring explicit synchronization.

package r4r.co.in.singleton.eager;

public class BillPughSingleton {

        private BillPughSingleton() {

                System.out.print("Bill Pugh Singleton......");

        }

        private static class SingletonHelper {

                private static final BillPughSingleton INSTANCE = new BillPughSingleton
();

        }

        public static BillPughSingleton getInstance() {

                return SingletonHelper.INSTANCE;

        }

}

  • When the getInstance() method is called for the first time, it triggers the loading of the SingletonHelper class.
  • When the inner class is loaded, it creates the INSTANCE of BillPughSingleton.
  • The final keyword ensures that the INSTANCE cannot be reassigned.

The Bill Pugh Singleton implementation, while more complex than Eager Initialization, provides a perfect balance of lazy initialization, thread safety, and performance, without the complexities of some other patterns like double-checked locking.

6. Enum Singleton

In this method, the singleton is declared as an enum rather than a class.

Java ensures that only one instance of an enum value is created, even in a multithreaded environment.

The Enum Singleton pattern is the most robust and concise way to implement a singleton in Java.

package r4r.co.in.singleton.enumsintone;

enum EnumSingleton {

        INSTANCE;

         public void doSomthing(){

                

        }

}

Many Java experts, including Joshua Bloch, recommend Enum Singleton as the best singleton implementation in Java.

However, it's not always suitable, especially if you need to extend a class or if lazy initialization is a strict requirement.

7. Static Block Initialization

This is similar to eager initialization, but the instance is created in a static block.

It provides the ability to handle exceptions during instance creation, which is not possible with simple eager initialization.

package r4r.co.in.singleton.eager;

public class StaticBlockInitializationSingleton {

        //static block Initialization

        private StaticBlockInitializationSingleton() {

                System.out.print("Singleton using Static Block Initialization...");

        }

        private static StaticBlockInitializationSingleton INSTANCE;

        static {

                try {

                        INSTANCE = new StaticBlockInitializationSingleton();

                } catch (RuntimeException e) {

                        throw new RuntimeException("Exception while creating singleton ");

                }

        }

        public StaticBlockInitializationSingleton getInstance() {

                return INSTANCE;

        }

}

  • The static block is executed when the class is loaded by the JVM.
  • If an exception occurs, it's wrapped in a RuntimeException.

It is thread safe but not lazy-loaded, which might be a drawback if the initialization is resource-intensive or time-consuming.

Real-World Examples of Singleton Design Pattern

Singleton is useful in scenarios like:

  • Managing Shared Resources (database connections, thread pools, caches, configuration settings)
  • Coordinating System-Wide Actions (logging, print spoolers, file managers)
  • Managing State (user session, application state)

Specific Examples:

  • Logger Classes: Many logging frameworks use the Singleton pattern to provide a global logging object. This ensures that log messages are consistently handled and written to the same output stream.
  • Database Connection Pools: Connection pools help manage and reuse database connections efficiently. A Singleton can ensure that only one pool is created and used throughout the application.
  • Cache Objects: In-memory caches are often implemented as Singletons to provide a single point of access for cached data across the application.
  • Thread Pools: Thread pools manage a collection of worker threads. A Singleton ensures that the same pool is used throughout the application, preventing resource overuse.
  • File System: File systems often use Singleton objects to represent the file system and provide a unified interface for file operations.
  • Print Spooler: In operating systems, print spoolers manage printing tasks. A single instance coordinates all print jobs to prevent conflicts.

Pros and Cons of Singleton Design Pattern

Pros

Cons

Ensures a single instance of a class and provides a global point of access to it

Violates the SIngle Responsibility Principle:- The pattern solves two problems at the same time .

Only one object is created ,which can be particularly beneficial for resource heavy classes .

In multithreaded environments ,special care must be taken to implement Singletons correctly to avoid race conditions .

Provides a way to maintain global state within an application

Introduces global state into an application,which might be difficult to manage .

Supports lazy loading ,where the instance is only created when it’s first needed

Classes using the singleton can become tightly coupled the singleton class

Guarantees that every object in the application uses the same global resource.

Singleton patterns can make unit testing difficult due to the global state it introduces

Top Blogs
All about the java programming language Published at:- When and Why Java is utilized for Application Advancement Published at:- Tips to learn Java Programming Language Published at:- Key Advantages of Java Application Advancement to Assorted Organizations Published at:- Scanner nextLine() ,nextInt() ,nextDouble() method in Java with Examples Published at:- java toUpperCase() and toLowerCase() example Published at:- pushing value at last in java | how to add element at the end of array in java Published at:- fizzbuzz problem java Published at:- Write a program for group words by first character of given string | Java 8 Stream Example Published at:- Write a Java 8 program to calculate the age of a person in years given their birthday Published at:- Write a Java 8 program to calculate the age of a person in years given their birthday Years Months Days Published at:- Write a Java 8 program to print the first 10 odd numbers Published at:- Filter employees by age in Java 8 Lamda steam Published at:- Write a Java 8 program to get the last element of an array string/object Published at:- Filter employees by age set senior if age is greater than 30 in Java 8 Lamda steam Published at:- How to increment salary by 2%, 5%, etc. Using java Published at:- Write a program to find the only duplicate count list in the List Published at:- Write a program to append char in char ex-input- {A, B, C} output->[A_X, B_Y, C_Z] Published at:- Write a program to sum an array without using the sum method Published at:- Write a program to sum an array Published at:- Drop all while condition not meet dropWhile(),dropWhile(Predicate<T> predicate) Published at:- Find the maximum value in a list of integers using Stream & Method Reference Published at:- How to sort a list of strings by length using Lambda expressions Published at:- How to filter and collect a list of strings that start with a specific letter using Java 8 Stream Published at:- Write a Java program To create a map from a array of strings where the key is the string and the value is its length Published at:- How to count the number of occurrences of a given word in a list of strings using Java 8 Published at:- How to remove all duplicates from an array of integers in Java using Java 8 Published at:- How to find next, previous, tomorrow ,yesterday date using Java 8 Published at:- How to iterate and modify values in a Map using Java 8 Published at:- How to print keys & values of a Map using Java 8 Published at:- count of each character in a String using Java 8 Published at:- Write a Program to find the Maximum element in an array Published at:- How to check if list is empty in Java 8 using Optional Published at:- Find duplicate elements with its count using Java 8 Published at:- Find Last duplicate character of given string using Java 8 Published at:- Given a list of integers, separate odd and even numbers Published at:- Singleton Design Pattern and 7 Ways to Implement It 4 Ways to Break Singleton Design Pattern Published at:- java 8 using lambda expression and stream api | Java 8 Programs using Lambda Expression and Stream Published at:- 26 Java 8 Programs using Lambda Expression and Stream Published at:- Java 8 Stream String Null Or Empty Filter Published at:- sum ,min ,max etc example using reduce method using Java 8 Stream API Published at:-
R4R.co.in Team
The content on R4R is created by expert teams.