DEV Community

Ravi Yasas
Ravi Yasas

Posted on

Singleton Design pattern

What is the design pattern?

  • In simple words, design patterns are best practices in the software development field.
  • These design patterns are invented by well experienced Object-Oriented Software developers using their practice and experience.

Singleton design pattern

  • This design pattern can be used to control object creation of the software development life cycle.
  • If you use the Singleton design pattern, then you can have only one instance of that type.

How to create a Singleton object?

  • Create private constructor (Then no one can instantiate this class, it means others can't create objects)
  • Create the only one private static instance
  • Create a public method to invoke this instance

Types of singleton implementations

There are several ways to implement a singleton class.

  • Eager initialization
  • Static block initialization
  • Lazy initialization
  • Thread-safe initialization
  • Enum initialization

Eager initialization

  • In this method, the instance is created at the time of class loading.
  • The instance is created even the client is requesting or not.
public class Singleton{
    private static final Singleton instance = new Singleton();
    private Singleton() { }
    public static Singleton getInstance() {
       return instance;
    }
}
Enter fullscreen mode Exit fullscreen mode

Static block initialization

  • This is very same as Eager initialization.
  • The special thing is, we use the static block in getInstance() method to have exception handling.
public class Singleton{

    private static Singleton instance;

    private Singleton() { }

    static{
        try {
            instance = new Singleton(); 
        }catch (Exception e) {
            System.out.println("Error : " + e);
        }
    }

    public static Singleton getInstance(){
        return instance;
    }
}
Enter fullscreen mode Exit fullscreen mode

Lazy initialization

  • This is a good one in a single-threaded environment.
  • But in a multithreaded environment, we have to use thread-safe initialization.
public class Singleton{

    private static Singleton instance;

    private Singleton() { }

    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
Enter fullscreen mode Exit fullscreen mode

The enum initialization

  • This is the most efficient way to implement a singleton.
  • Because it is very easy to write. Here is the way to implement it.
public enum EnumSingleton{
      instance;
}
Enter fullscreen mode Exit fullscreen mode
  • You can get the instance by calling EnumSingleton.instance

Thread-safe initialization

  • This is just very similar to Lazy initialization.
  • But here synchronize the method that can be used to get the instance in a multi-threaded environment.
public class Singleton {

    private volatile static Singleton instance;

    private Singleton() { }

    public static Singleton getInstance() { 
        if (instance == null) {
             synchronized (Singleton.class) {
                  if (instance == null) {
                        instance = new Singleton();
                  }
             }
        }
        return instance;
    }
}
Enter fullscreen mode Exit fullscreen mode

What is the double-checking on the Singleton design pattern?

  • Just think, you are using the code like below.
synchronized (ThreadSafe.class){
    if(instance ==null){
         instance = new ThreadSafe();
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Here only one thread can acquire the lock of the object.
  • If many threads want to get the instance, all threads need to wait until one thread releases the lock of the object.
  • Since the synchronized block is using heavy CUP usage, it will consume more memory.
  • To resolve this, we can double-check the instance as follows.
if(instance ==null){
   synchronized (ThreadSafe.class){
       if(instance ==null){
           instance = new ThreadSafe();
       }
   }
}
Enter fullscreen mode Exit fullscreen mode
  • Now other threads will not reach the synchronized block. This will save CPU memory.

What is the use of Volatile?

  • The volatile keyword can be used with variables.
  • Volatile variables will not be cached in the cache memory.
  • It will be saved only in the main memory.
  • If one thread changed the value, all other threads can also see the changed value.

Which is the best one?

  • The enum singleton implementation is the best way because it is very easy to implement and use.
  • But this is available since Java 5.

When to use the Singleton design pattern?

  • To manage shared resources(Database connections, file manager)
  • Logging
  • Catching

Singleton in JDK

There are many singleton classes that can be found in JDK. I listed three of them.

  • In java.lang.Runtime which provides getRuntime() method.
  • In java.awt.Toolkit which provides getDefaultToolkit() method.
  • In java.awt.Desktop which provides getDesktop() method.

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay