Patterns
YouTube Video for the Singleton Pattern in Java and Python
This article exists on YouTube

The entire content of this article is also available on YouTube. It's your choice: if you prefer video content, you can watch it on YouTube. If you prefer reading, feel free to continue here.

Head over to the YouTube video

What is a Singleton Pattern?

The Singleton Pattern is a programming pattern used in software engineering and it is part of the group of creational patterns. It may be used in any object-oriented programming language, such as Java, Python, C++, and so on. What it does is to ensure that any other place within the same application only gets one single instance of it upon instantiation. At all times there can only be one object of a class that has the Singleton Pattern implemented.

So what is this Singleton Pattern used for? It is useful when exactly one object is needed to coordinate actions across the system, such as managing resources that should be shared by the entire application. Examples of real-world use include logging classes, database connections, configuration managers, or printer spooler.

Logger Classes
Many applications make use of loggers within their code to record various events. As the entire application usually only has a single logger, it makes sense to also access the exact same logger from within the code. A Singleton logger enables this by ensuring that only one instance of the logger exists.

Database Connection
Most applications store their data within databases and usually there is only one database connection. This saves resources and also limits the amount of open connections. A Singleton for the database ensures that every part within the code accesses the same connection.

Configuration Manager
A Singleton configuration manager can be used to manage application parameters and settings needed by different parts of the application.

Printer Spooler
Within operating systems a Singleton can be used to coordinate access to the printer spooler, ensuring that only one instance of the spooler runs at a time and processes print jobs in the correct order.

What is the structure of a Singleton Pattern?

  1. Private Constructor
    Setting the constructor to private prevents the instantiation of the class from external classes. That means that the Java keyword new cannot be used to create an instance of this class.
  2. Static Method
    A static method provides a global access point to the instance of the class. Any name can be chosen, but getInstance() clearly communicates the intent of the method. This method serves as a replacement of the Java new keyword that would be used if we would remain with a public constructor.
  3. Static Instance
    A static variable holds the sole instance of the class. It does not need the class to be instanciated in order to be used. This variable is set to private as we only want to grant access to it through the getInstance() method.
  4. Lazy Initialization
    The instance is typically created lazily, meaning that instantiation only takes place when the getInstance() method is called. This helps in conserving resources if the object is not needed. Due to the fact that the constructor is set to private it is not possible to create any instance oneself anymore. Instead, the instance is now created by the class itself within the getInstance() method.

Example Codes

There are a number of programming languages where the Singleton Pattern can prove useful. Every language that supports the construct of classes can make use of this pattern.

All the codes within this article can also be found on the GitHub repository programming-patterns and in there within the directory Singleton Pattern.

Java Example

The following example is a Java application putting the Singleton Pattern into action. All the following files need to be placed into the same folder so that the code within the files can work properly, because the files also reference each other. As this is the smallest possible code example, this little project only consists of the two Java files Singleton.java and Main.java.

It is essentially the static keyword for the private variable instance, denoting that a member like variables or methods belongs to the class itself, rather than to instances of the class. By declaring the instance variable as static, it becomes associated with the class Singleton rather than any specific instance of the class. This means there will be only one instance of instance shared among all instances of the Singleton class.

public class Singleton {
  private static Singleton instance;
  private String message;

  private Singleton() {}

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

  public void setMessage(String message) {
      this.message = message;
  }

  public void showMessage() {
      System.out.println(this.message);
  }
}

Within the Main class the Singleton class is instanced twice into different variables (s1 and s2) using the getInstance() method. The first call of getInstance() finds out that there is no instance of Singleton yet and therefore creates a new one and returns it to the caller. The second call of getInstance() finds the already existing instance and therefore does not create a new instance and returns the existing one instead.

The setMessage(...) calls on the variables s1 and s2 each set the private message variable within their instances, but as they have the same instance the second call of setMessage(...) overwrites the private message variable. The showMessage() method call on the variables s1 and s2 proves it.

public class Main {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();

        s1.setMessage("Hello s1!");

        s1.showMessage();
        s2.showMessage();

        s2.setMessage("Hello s2!");

        s1.showMessage();
        s2.showMessage();
    }
}

There also needs to be a Manifest.txt file within the same folder. This is a metadata file used primarily in JAR files. It contains information about the JAR file itself and its contents. It is placed within thie META-INF folder within the JAR archive file structure.

Main-Class: Main

To compile this code into an executable Java application which would be a JAR file, a couple of commands need to be executed from within the same directory. The commands are found within the build file.

build.cmd (Windows)
@echo off

javac *.java
jar cvfm SingletonDemo.jar Manifest.txt *.class
build (MacOS / Linux)
#!/bin/bash

javac *.java
jar cvfm SingletonDemo.jar Manifest.txt *.class

Now that the compilation has taken place, there are new files within the same directory. Every JAVA file has its equivalent CLASS file, and there is also a file called SingletonDemo.jar. This is the Java application that needs to be executed. The command for that is within the run file.

run.cmd (Windows)
@echo off

java -jar SingletonDemo.jar
run (MacOS / Linux)
#!/bin/bash

java -jar SingletonDemo.jar

Testing the Java Example

Now that all the files are ready and within their correct location they can be put to test. First we need to compile the Java code and then we can execute it to see what it will print in the Windows Command Prompt or in the MacOS / Linux Terminal.

build.cmd (Windows)

build.cmd (Windows)

build (MacOS / Linux)

build (MacOS / Linux)

run.cmd (Windows)

run.cmd (Windows)

run (MacOS / Linux)

run (MacOS / Linux)

Python Example

The following example is a Python application putting the Singleton Pattern into action. All the following files need to be placed into the same folder so that the code within the files can work properly, because the files also reference each other. As this is the smallest possible example, this little project only consists of the two Python files singleton.py and main.py.

class Singleton:
  _instance = None

  def __new__(cls):
      if cls._instance is None:
          cls._instance = super().__new__(cls)
      return cls._instance

  def setMessage(self, message):
      self._message = message

  def showMessage(self):
      print(self._message)

Within the main function the Singleton class is instanced twice into different variables (s1 and s2) using the constructor method __new__. The first call of the constructor method finds out that there is no instance of Singleton yet and therefore creates a new one and returns it to the caller. The second call of the constructor method finds the already existing instance and therefore does not create a new instance and returns the existing one instead.

The setMessage(...) calls on the variables s1 and s2 each set the instance variable _message within their instances, but as they have the same instance the second call of setMessage(...) overwrites the same instance variable _message. The showMessage() method call on the variables s1 and s2 proves it.

from singleton import Singleton

def main():
  print("Singleton Pattern in Python")
  print("---------------------------")
  print()
  
  s1 = Singleton()
  s2 = Singleton()

  print("Same instance in s1 and s2: ", end="")
  print(s1 is s2)

  s1.setMessage("Hello s1!")

  s1.showMessage()
  s2.showMessage()

  s2.setMessage("Hello s2!")

  s1.showMessage()
  s2.showMessage()

if __name__ == "__main__":
  main()

There is no need to compile anything in Python. The code is executed directly using the python command under Windows and the python3 command under MacOS / Linux.

run.cmd (Windows)
@echo off

python main.py
run (MacOS / Linux)
#!/bin/bash

python3 main.py

Testing the Python Example

Now that all the files are ready and within their correct location they can be put to test. Python does not need to be compiled before being run. Therefore we can execute it right away to see what it will print in the Windows Command Prompt or in the MacOS / Linux Terminal.

run.cmd (Windows)

run.cmd (Windows)

run (MacOS / Linux)

run (MacOS / Linux)

What about Multi-Threading?

When it comes to accessing the Singleton class through multiple threads at runtime, the classic Singleton Pattern can run into competition errors. This is due to the fact, that in such situations there is no way to know what thread currently executes what part of code within the class. If a thread has entered a method and checked for the existence of a certain static variable, while another thread has done exactly that just one step before, then the next step could be to write something into that variable. As both threads have checked the variable for the possibility to write into it and have both gotten the ok to do so, they will now both write into it. The problem is, that thread that writes second after the first thread, will overwrite what ever has been written into the variable. This can lead to unexpected code behavior and hence needs to be addressed when making use of multithreading.

The first approach could be to add the Java keyword synchronized to the getInstance() method. Technically, this solves the matter. When accessing the Singleton class with multiple threads at the same time, they will have to wait on one another. Never will there now be a competition for the getInstance() method.

public class Singleton {
    private static Singleton instance;
    private String message;

    private Singleton() {}

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

    public void setMessage(String message) {
        this.message = message;
    }

    public void showMessage() {
        System.out.println(this.message);
    }
}

While this example works well from a technical perspective, we now have the situation, that threads wait for each other, and doing so they are idle. Hence, this now has become a performance issue. This can easily be solved, when switching from a lazy aproach of instantiation to an eager one. This can be achieved by creating the instance directly to the static instance-variable. This way there is a guarantee that the instance exists and there is no need to check if the instance exists from within the getInstance() method.

public class Singleton {
  private static Singleton instance = new Singleton();
  private String message;

  private Singleton() {}

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

  public void setMessage(String message) {
      this.message = message;
  }

  public void showMessage() {
      System.out.println(this.message);
  }
}

If the desire is to still remain with the lazy approach and still keep the class thread-safe, then the double-checked locking approach can prove valuable. Within this approach, the instance-variable is first checked for an already existing instance. If there is one it is returned and the job is done. If there is none there still could be more than one thread already having checked and gotten to know that there is no instance yet. To prevent them both from creating one instance after the other, we now create a synchronized block and within this one we check again if there is an instance and if not we create one. The other threads would have to wait for the instance to be created and then check if the instance exists, and as the instance now exists, the job is already done and the instance will just be returned to them and not created again.

The static instance variable also needs to get the keyword volatile. In situations of competing threads there is no guarantee that a thread accessing a static variable will get the expected result of another thread that has previously accessed the same static variable. This happens due to a command reordering functionality implemented in Java. By setting the keyword volatile the reordering will not be allowed and therefore the expected result will be exactly what it is thought to be.

public class Singleton {
  private volatile static Singleton instance = new Singleton();
  private String message;

  private Singleton() {}

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

  public void setMessage(String message) {
      this.message = message;
  }

  public void showMessage() {
      System.out.println(this.message);
  }
}

What about Reflection?

Reflection is a feature in many programming languages allowing to inspect and manipulate the structure of classes, methods, and variables at runtime. Reflection also allows to access the private constructor of a class, which in the case of the Singleton pattern is used to restrict instantiation. Once access is done, multiple instances of the class can be created, effectively breaking the Singleton pattern.

Also, Reflection allows to change the Singleton instance state, bypassing any methods or mechanisms put in place for controlling access to it. As a result this may lead to unexpected behavior and violate the intended usage of the Singleton Pattern.

What about Serialization and Deserialization?

Serialization is a process in many programming languages enabling to convert objects into a format that can be stored and transmitted and later reconstructed back into objects. Often the format it is converted in is JSON or XML. When deserializing back into an object the process involves creating an instance of that given object and entering the stored parameters. If there are multiple objects, then multiple instances are created. In the case of objects implementing the Singleton pattern, the principle of creating only one single instance of that class is violated.

Is the Singleton Pattern an Anti-Pattern?

The Singleton Pattern is a Design Pattern and not an Anti-Pattern. There are arguments by many people online with the desire though to avoid the Singleton Pattern. Some people argue that it makes the code more complex and less useful. There also are comments about its re-use and its testability. Also, the Singleton Pattern tightly couples the code, in constrast to the principles of loose coupling. Furthermore, the Singleton Pattern violates the single-responsibility principle due to the fact that a class usually does more than only ensuring that it is the only instance within an application. Moreover, when applied in the wrong way because of a solution to a verdantly understood problem, it may not provide the intended simplification, ignoring difficulties that may be introduced. There have been comments on using Dependency Injection instead of the Singleton Pattern. While there may be a slice of truth with all these comments and arguments about this pattern, the one implementing it into an application has to be the judge towards accepting its disadvantages and profiting from its benefits.

More Information

So, where do I have my information from? In general, there are lots of places on the internet that offer great information. But that is just one source of information. Another source would be books. Those have the advantage that usually several people work on the same book before it is released, raising the chance for distribution of good and proven information.

Head First - Design Patterns

Building Extensible and Maintainable Object-Oriented Software

A book that has proven to be a valuable asset within my personal library is Head First - Design Patterns by the publisher O'Reilly. It has a fun approach to this topic, having recurring characters, such as the Guru, the Developer, the Skeptical Developer, Joe, and many more.

Java Design Patterns

A Hands-On Experience with Real-World Examples

Another highly valuable book is Java Design Patterns: A Hands-On Experience with Real-World Examples by the publisher Apress. It offers a conservative and rather scientific approach to the subject. It also offers code examples in Java, although any object-oriented programming language applies to the design patterns shown here.

We use cookies

We deeply value your privacy and want to ensure you have the best possible experience on our website. By accepting our Cookie Consent, you're helping us tailor your visit to your preferences, providing you with personalized content and ensuring that all features work seamlessly.

However, if you choose not to accept our Cookie Consent, some parts of the website may not function optimally. We want you to enjoy full access to all the great content and features we offer, so we encourage you to consider accepting our Cookie Consent.

Please be aware that even if you choose not to accept our Cookie Consent, you can still browse our website. However, some functionalities may be limited, and you may not experience the website to its fullest potential.

For more details on how we handle your data, please refer to our Privacy Policy.