HFDP(5) - Singleton Pattern

jzfrank

jzfrank

Posted on January 16, 2023

HFDP(5) - Singleton Pattern

In this post we will introduce the Singleton Pattern.

In many ways, Singleton is very like the global variables. But Singleton could be lazily loaded. Singleton Pattern ensures there is at most one instance of a class and that is globally accessible. For example, we may want the database connection and logging to be a singleton.

Singleton is a class with private constructors. The only way to get an instance of it is via a static method getInstance.

Formal Definition

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

Implementation

For Single Thread (non thread-safe)

public class Singleton {
    private static Singleton uniqueInstance;

    // other useful instance variables here

    private Singleton() {
        // initialize
    }

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

    // other useful methods here
}
Enter fullscreen mode Exit fullscreen mode

However, if java runs multithread, unqueInstance might be created more than once. This is not what we want.

Synchronized

It is straightforward to solve the thread safety issue by adding synchronized keyword to getInstance method. (TODO: ...detailed explanation here... )

public class Singleton {
    private static Singleton uniqueInstance;

    // other useful instance variables here

    private Singleton() {
        // initialize
    }

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

    // other useful methods here
}
Enter fullscreen mode Exit fullscreen mode

However, synchronization is expensive.

Eager Initialization

public class Singleton {
    private static Singleton uniqueInstance = new Singleton();

    // other useful instance variables here

    private Singleton() {
        // initialize
    }

    public static Singleton getInstance() {
        return uniqueInstance;
    }

    // other useful methods here
}
Enter fullscreen mode Exit fullscreen mode

If the Singleton is bound to be used, we could use eager initialization, making sure the instance is available from the start. This certainly solves the expensive synchronization issue.

However, one problem with this approach is if the Singleton is resource intensive (initialization is expensive), and we may not use it in the whole program. It is advised to turn to other methods.

Double-checked locking

public class Singleton {
    private volatile static Singleton uniqueInstance;

    // other useful instance variables here

    private Singleton() {
        // initialize
    }

    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            // Check for an instance and if there isn’t one,
            // enter a synchronized block.
            synchronized (Singleton.class) {
                // Note we only synchronize the
                // first time through
                if (uniqueInstance == null) {
                    // Once in the block, check again and if
                    // still null, create an instance.
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }

    // other useful methods here
}
Enter fullscreen mode Exit fullscreen mode

If performance is an issue, use this method. However, it might be an overkill for some simpler problems.

Diagram

Singleton

Singleton Pattern is probably the most simple design pattern. That's it for today. See you next post!

💖 💪 🙅 🚩
jzfrank
jzfrank

Posted on January 16, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related