JavaDesign patterns

Singleton

Sometimes we need to have only a single instance of a class shared across an entire application. There is a special design pattern called Singleton that restricts the instantiation of a class to one object. The pattern ensures that only one instance of the class ever exists and provides global access to the instance for the outer world.

The same instance is used by different clients (classes, methods)

Singletons often control access to resources, such as database connections or sockets.

For example, a class which keeps a connection to a database can be written as a singleton because creating every time a connection object is bulky for memory. If it is a singleton, then your application will perform better and faster.

Another example is a class that provides a universal logger for an application. It keeps the shared log-file as the resource.

In this topic, we will consider only the basic singleton implementation.

The basic singleton in Java

The standard way to write a class according to the singleton pattern includes:

  • a private constructor to defeat the creation of instances using the keyword new;
  • a private static variable of the class that is the only instance of the class;
  • a public static method to return the same instance of the class; this is the global access point to the instance.

The following code implements the concepts above.

class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton() { }

    public static Singleton getInstance() {
        return instance;
    }
}
The presented class is quite simple, but let's look at everything in order.
The class Singleton is a basic implementation of the considered pattern. The field instance stores only a single instance of the class. The constructor is declared as private to defeat instantiation. The static method getInstance returns the same instance of the class.

Let's create three variables, assign an instance to each of them and then compare the variables by references.

Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
Singleton s3 = Singleton.getInstance();
        
System.out.println(s1 == s2); // true because s1 and s2 refer the same object
System.out.println(s2 == s3); // true because s2 and s3 refer the same object

As you can see, the variables s1s2, and s3 refer the same object that is stored in the static field of Singleton.

Usually, singletons have additional instance fields to store values (global variables) to share them across your application as well as methods to have a behavior.

Lazy initialization

The singleton above load the instance when the class is loaded. But sometimes initialization of a singleton can take much time. For example, to load values of fields from a file or a database.

The following implementation loads the instance only it is needed to a client (who calls getInstance).
class Singleton {
    
    private static Singleton instance;
    
    private Singleton () { }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Despite the fact that the implementation of the singleton pattern contains minimum lines of code, it has an important feature - the singleton has a lazy initialization. It means the singleton instance is not created until the getInstance method is called for the first time. This technique ensures that singleton instances are created only when needed.

Important, use the provided singleton class only in one-thread environments because it suffers from a multithreading issue. In other topics, we will consider techniques to write thread-safe singletons.

The singleton pattern in Java libraries

There are a lot of Singleton examples in the Java Class Library:

To determine a singleton, see a static creational method which always returns the same instance of a class.

Popular frameworks for developing enterprise applications (such as Spring, Java EE) also use singletons.

Criticism

There are some who are critical of the singleton pattern and consider it to be an anti-pattern in that it is frequently used in scenarios where it is not beneficial, introduces unnecessary restrictions in situations where a some instance of a class is not actually required and introduces global state into an application. Use the pattern wisely when you really need a singleton.

How did you like the theory?
Report a typo