Singleton pattern

Definition

The Singleton pattern ensures a class has only one instance in the JVM, and provides a global point of access to it.

Purpose

Singleton controls concurrent access to resources.

When to use the Singleton Design Pattern?

  1. We should use the Singleton Design Pattern when we want to share a single object among multiple users/callers. For example, a database connection.
  2. We should use the Singleton Design Pattern when we want stricter control over global variables. Remember, no one except the Singleton class itself can replace the cached instance.

Overview

Using Singleton pattern, we create one-of-a-kind objects for which there is only one instance. This is the simplest in terms of it’s class diagram; in fact, the diagram holds just one class. Despite its simplicity from a design class design perspective, there are quite a few bumps and potholes in its implementation.

Why to use the Singleton Design Pattern?

There are many objects we only need one of; connection or thread pools, caches, dialog boxes, objects that handle preferences and registry settings, objects used for logging, and objects that act as device drivers to devices like printers and graphic cards. For many of these type of objects, if we were to instantiate more than one, we would run into all sorts of problems like incorrect program behavior, overuse of resources, or inconsistent results. Using Singleton classes, we can assure that every object in your application is making use of the same global resource.

Why do we need this pattern? If there are classes that should only be instantiated once, can’t we just do this by convention or by global variables? In java, we can do it with static variable. The Singleton pattern is a time-tested method for ensuring only one object (one instance of the class) gets created. The pattern also gives us a global point of access, just like a global variable, but without the downsides. What is an example of a downside? If you assign an object to a global variable, then that object might be created when your application begins. What if this object is resouce intensive and your application never ends up using it? With Singleton pattern, we can create our objects only when they are needed.

There are situations in which a singleton class is useful. Typical examples are classes that we could shortly describe as “managers”. These are classes which manage resources, read data from configuration files, instantiate threads etc. If you were making a role-playing game, you would probably have multiple “Item” objects or multiple “Level” objects, but it would make sense to make the “Score” class singleton – since you only need one object to take care of the player’s score.

Another example could be a factory with multiple manufacturing tracks. The tracks are the ones that actually do all the work, whether it is packing cans or making car parts. However, it is the “factory manager” that decides how many tracks will be working, for how long, and what they are going to do.

Real world examples

Here is the list of some of the known real world example using the singleton pattern:

  1. Logger : In enterprise applications, the Logger object is a real-world example of a Singleton pattern. If this class is not a singleton, there will be a new log file created for every user call (client applications). All the logs will be written in a single file using this design.
  2. Cache : To have a global point of reference, it can also create the cache classes as Singleton objects. Once again, in real-life client applications will interact with the same cache objects for cache entries.
  3. Configuration File : In enterprise applications, the configuration/properties can be based on the Singleton pattern. With this, multiple client applications will use the same files (that’s the idea anyway, that configuration mostly remains the same for all the clients).
  4. JDK / Spring uses Singleton Pattern
    1. java.lang.Runtime#getRuntime()
    2. java.awt.Desktop#getDesktop()
    3. java.lang.System#getSecurityManager()
    4. Spring Bean Scope

Steps to build a Singleton class

  1. In multithreaded applications, lazy instantiation can cause race conditions. Therefore, use double-checked locking to prevent the creation of multiple instances by different threads
public MyClass {

}

How would we create a new object of this class? new MyClass()

1. make the constructor private

Now, lets make it’s constructor private.

public MyClass {
    private MyClass() {}
}

The constructor is declared private.

Now, MyClass cannot be instantiated from anywhere outside of the code in MyClass itself.

Only Singleton (the current class) can instantiate this class.

2. Declare a static volatile class variable for the instance of this class

private static volatile MyClass uniqueInstance = null;

uniqueInstance is the static variable to hold the one instance of the class Singleton.

The volatile keyword ensures that multiple threads handle the uniqueInstance variable correctly when it is being instantiated to the Singleton instance.

3. provide the instance of this class to other places in the application using a public static volatile method

If no other object can instantiate an object of MyClass, how is it going to be useful? We need a way to provide the instance of this class to other places in the application. How do we do that? By putting a static method in it. The static method can be called like this: MyClass.getInstance()

public MyClass {

  private static volatile MyClass uniqueInstance = null;

  private MyClass() {}

  public static MyClass getInstance() {}

}

getInstance() gives a way to instantiate the class and also to return an instance of it. To get a hold of an Singleton object, we don’t instantiate one, we just ask for an instance.

4. Consider lazy-initialization or eager-initialization

Eager-initialization

If the overhead of creation and runtime aspects of the Singleton are not that bad, you can do this: Move to an eagerly created instance rather than a lazily created one.

public class Singleton {

  private static final Singleton INSTANCE = new Singleton();

  private Singleton() {}

  public static Singleton getInstance() {
    return INSTANCE;
  }
}

Using this approach, we rely on the JVM to create the unique instance of the Singleton when the class is loaded. The JVM will guarantee that the instance will be created before any thread accesses the static uniqueInstance variable.

Lazy-initialization

If performance implications of creating the Singleton at application start-up or for some other reasons, the Singleton cannot be created until it is requested the first time, use lazy-initialization to not create the intance until the static getter is called the first time.

The instance is lazily created (it is created when someone asks for it) instead of getting eagerly created.

public class MyClass {

  private static volatile MyClass uniqueInstance = null;

  // other useful instance variables here

  public static MyClass getInstance() {
    uniqueInstance = new MyClass();
    return uniqueInstance;
  }

  // other useful methods here
}

5. Handle multi-threading by using synchronized keyword

The multithreading woes can be fixed my making getInstance() a synchronized method:

public static synchronized MyClass getInstance() {
    if (uniqueInstance == null) {
        uniqueInstance = new MyClass();
    }
    return uniqueInstance;
}

By adding the synchronized keyword to getInstance(), we force every thread to wait its turn before it can enter the method. That is, no two threads may enter the method at the same time.

6. Consider the implications of synchronizing

It is expensive to synchronize the getInstance() method. Synchronizing a method can decrease performance by a factor of 100.

So, what do we do? Here are a few options.

Don’t use synchronization

Do nothing if the performance of getInstance() is not critical to the application.

If calling the getInstance() method is not causing substantial overhead for your application, don’t do anything. Synchronizing getInstance() is straightforward and effective. If a high-traffic part of your code begins using getInstance(), you may have to reconsider.

Use double-checked locking before synchronizing

If synchorization absolutely needs to be used, consider double-checked locking to reduce the use of synchronization

Use double-checked locking to reduce the use of synchronization in getInstance()

With this approach, we first check to see if an instance is created, and if not, then we synchronize. This way, we only synchronize the first time. In the synchronized block, check again and if still not null, create an instance.

public class Singleton {

  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;
  }
}

If performance is an issue in your use of the getInstance() method, then this method of implementing the Singleton can drastically reduce the overhead.

Difference between having a singleton and not having a singleton

We have a class that is not Singleton.

public class ChocolateBoiler {

  private boolean empty;
  private boolean boiled;

  public ChocolateBoiler() {
    empty = true;
    boiled = false;
  }

  public void fill() {
    if (isEmpty()) {
      empty = false;
      boiled = false;
      // fill the boiler with a milk/chocolate mixture
    }
  }

  public void drain() {
    if (!isEmpty() && isBoiled()) {
      // drain the boiled milk and chocolate
      empty = true;
    }
  }

  public void boil() {
    if (!isEmpty() && !isBoiled()) {
      // bring the contents to a boil
      boiled = true;
    }
  }

  public boolean isEmpty() {
    return empty;
  }

  public boolean isBoiled() {
    return boiled;
  }

}

If two ChocolateBoiler instances get loose, some very bad things can happen due to the functionality in the fill(), drain() and boil() methods.

Lets turn this into a Singleton.

public class ChocolateBoiler {

  private boolean empty;
  private boolean boiled;

  private staic ChocolateBoiler  uniqueInstance;

  private ChocolateBoiler() {
    empty = true;
    boiled = false;
  }


  public static ChocolateBoiler getInstance() {
    if (uniqueInstance == null) {
      uniqueInstance = new ChocolateBoiler();
    }
    return uniqueInstance;
  }

  public void fill() {
    if (isEmpty()) {
      empty = false;
      boiled = false;
      // fill the boiler with a milk/chocolate mixture
    }
  }

  public void drain() {
    if (!isEmpty() && isBoiled()) {
      // drain the boiled milk and chocolate
      empty = true;
    }
  }

  public void boil() {
    if (!isEmpty() && !isBoiled()) {
      // bring the contents to a boil
      boiled = true;
    }
  }

  public boolean isEmpty() {
    return empty;
  }

  public boolean isBoiled() {
    return boiled;
  }

}

Despite the fact we improved the code using Classic Singleton, there is a possibility that two instances of ChocolateBoiler can get instantiate. How? Two separate threads can call ChocolateBoiler.getInstance() at the same time. And that can result in two different objects being returned. There can be two ChocolateBoiler instances.

How to fix this?

Can we just create a class in which all methods and variables are defined as static? Wouldn’t that be the same as a Singleton?

Yes, if your class is self-contained and doesn’t depend on complex initialization. However, because of the way static initializations are handled in Java, this can get very messy especially if multiple classes are involved. Often, this scenario can result in subtle, hard-to-find bugs involving order of initialization. Unless there is a compelling need to implement your “singleton” this way, it is far better to stay in the object world.

Gotchas

If you are using multiple classloaders and Singletons, be careful. If you have two or more class loaders, you can load the same class multiple times. If that class happens to be a Singleton, then since we have more than one version of the class, we also have more than one instance of the Singleton. One way around this problem is to specify the classloader yourself.

Conclusion

These are very valid arguments. However, Singletons are useful in situations like the ones we’ve discussed in the previous paragraphs, when one class needs to manage resources for other classes and when having more instances than one would truly be a design flaw. With prudent, moderate usage and implementations which can be optimized for thread-safety, serialization or faster performance, the singleton pattern can improve the overall readability and elegance of your code. This design pattern should not be avoided since the Singleton Design Pattern is, after all, a classic Gang of Four design pattern.

Internal Implementation

https://github.com/explorer436/programming-playground/tree/main/java-playground/design-pattern-samples/design-pattern-examples

Reading material

https://www.javadevjournal.com/java-design-patterns/singleton-design-pattern/

Questions

What feature of java helps implement this pattern?

https://github.com/explorer436/my-personal-things/blob/master/programming/Interviews/Interview%20questions/Design%20patterns%2C%20programming%20principles%20and%20system%20design/Singleton%20pattern.org

Tags

  1. Thread synchronization
  2. Thread safety
  3. Synchronized keyword
  4. Singleton pattern - breaking Singleton
  5. Singleton pattern - arguments against it