loading...

Design Pattern: The Singleton Pattern

danlee0528 profile image Daniel Lee ・2 min read

The Singleton Pattern ensures a class has only one instance and provides a global point of access to it.

For example, a very simple singleton class can look something like this:

public Myclass{
    // class can't be instantiated because of the 'private' constructor
    private MyClass() { }
    
   // It is a CLASS method. It needs the class name to refer to a static method - MyClass.getInstance()
    public static MyClass getInstance(){
          return new MyClass();
    }
}

At this point, you may have thought how a singleton pattern can be used for multi-threaded situations such as resource pool management (thread pools, connection pools, etc.) and registry setting (you want to have only one copy of registry information of your computer). Consider the following example.

public class Singleton{
    private static Singleton UniqueInstance;

    // other useful instance variable here

    private Singleton() { }

    // In java, 'synchronized' forces each thread to wait its time before it can enter the method
    public static synchronized Singleton getInstance(){
        if (UniqueInstance == null){
            UniqueInstance = new Singleton();
        }    

        return UniqueInstance;
    }

    // other useful methods here
}

Did you notice something in the code above? You're right, every thread will enter the "getInstance()" method and check if there's a 'UniqueInstance' created every time. This is a overhead. Imagine, if you have a program with hundreds of threads accessing the method and checking the condition for each one of them, it will slow down your program.

To improve multi-threading,

  1. Do nothing if the performance of getInstance() isn't critical to your application
  2. Move to an eagerly created instance rather than a lazily created one
    public class Singleton{
    private static Singleton UniqueInstance = new Singleton();
    private Singleton() { }
    public static Singleton getInstance(){
         return uniqueInstance;
    }
    }
    
  3. Use "double-checked locking" to reduce the use of synchronization in getInstance(); first check if an instance is created, if not, then synchronize
public class Singleton{
    // volatile ensures that multiple threads handle the uniqueInstance correctly 
    // when it is being initialized to the singleton sintance
    private volatile static Singleton UniqueInstance;

    private Singleton() { }

    public static Singleton getInstance(){
        if (UniqueInstance == null){
            synchronized (singleton.class){
                if (uniqueInstance ==null){
                    uniqueInstance = new Singleton();
                }
            }
        }    
        return UniqueInstance;
    }
}

Discussion

pic
Editor guide