Java Singleton Pattern Example Code

Overview

In this article we will discuss the following points:

Table of Contents

1. Intent

2. Explanation

3. Structure

4. Participants

5. Implementation

5.1 Thread-Safe Singleton

5.2 Double check locking

5.3 Eager Initialization

5.4 Enum Singleton

6. Applicability

6.1 Typical Use Case

7. Real world examples

8. Consequences

1. Intent

Ensure a class only has one instance, and provide a global point of access to it.

2. Explanation

Real world example

There can only be one ivory tower where the wizards study their magic. The same enchanted ivory tower is always used by the wizards. The ivory tower here is a singleton.

In plain words

Ensures that only one object of a particular class is ever created.

Wikipedia says

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.

3. Structure

4. Participants

Singleton

  • Defines an Instance operation that lets clients access its unique instance.

The instance is a class operation

  •  May be responsible for creating its own unique instance.

Tips to create Singleton design pattern

To create the singleton class, we need to have a static data member of the class, private constructor, and static factory method.

  • Static member: It gets memory only once because of static, it contains the instance of the Singleton class.
  • Private constructor: It will prevent to instantiate the Singleton class from outside the class.
  • Static factory method: This provides the global point of access to the Singleton object and returns the instance to the caller.

5. Implementation

5.1 Thread-Safe Singleton

Lazy initialization method to implement Singleton pattern creates an instance in the global access method. Here is the sample code for creating Singleton class with this.

The instance is lazily initialized and thus needs a synchronization mechanism.

                          package              com.ramesh.singleton;                          public              final                              class                ThreadSafeLazyLoadedIvoryTower              {              private              static              ThreadSafeLazyLoadedIvoryTower instance;                              private                ThreadSafeLazyLoadedIvoryTower                ()              {              // to prevent instantiating by Reflection call              if              (instance !=              null) {              throw              new              IllegalStateException("Already initialized.");     }   }              /**    * The instance gets created only when it is called for first time. Lazy-loading    */                              public                static                synchronized                ThreadSafeLazyLoadedIvoryTower                getInstance                ()              {              if              (instance ==              null) {       instance =              new              ThreadSafeLazyLoadedIvoryTower();     }              return              instance;   } }          

Above implementation works fine and provides thread-safety but it reduces the performance because of the cost associated with the synchronized method, although we need it only for the first few threads who might create separate instances. To avoid this extra overhead every time, the double-checked locking principle is used. In this approach, the synchronized block is used inside if condition with an additional check to ensure that only one instance of a singleton class is created.

5.2 Double check locking

                          public              final                              class                ThreadSafeDoubleCheckLocking              {              private              static              volatile              ThreadSafeDoubleCheckLocking instance;              /**    * private constructor to prevent client from instantiating.    */                              private                ThreadSafeDoubleCheckLocking                ()              {              // to prevent instantiating by Reflection call              if              (instance !=              null) {              throw              new              IllegalStateException("Already initialized.");     }   }              /**    * Public accessor.    *    *                @return                an instance of the class.    */                              public                static                ThreadSafeDoubleCheckLocking                getInstance                ()              {              // local variable increases performance by 25 percent              // Joshua Bloch "Effective Java, Second Edition", p. 283-284              ThreadSafeDoubleCheckLocking result = instance;              // Check if singleton instance is initialized. If it is initialized then we can return the instance.              if              (result ==              null) {              // It is not initialized but we cannot be sure because some other thread might have initialized it              // in the meanwhile. So to make sure we need to lock on an object to get mutual exclusion.              synchronized              (ThreadSafeDoubleCheckLocking.class) {              // Again assign the instance to local variable to check if it was initialized by some other thread              // while current thread was blocked to enter the locked zone. If it was initialized then we can                            // return the previously created instance just like the previous null check.              result = instance;              if              (result ==              null) {              // The instance is still not initialized so we can safely (no other thread can enter this zone)              // create an instance and make it our singleton instance.              instance = result =              new              ThreadSafeDoubleCheckLocking();         }       }     }              return              result;   } }          

5.3 Eager Initialization

In eager initialization, the instance of Singleton Class is created at the time of class loading, this is the easiest method to create a singleton class but it has a drawback that instance is created even though client application might not be using it.

Eagerly initialized static instance guarantees thread safety.

                          package                              com.ramesh.singleton;              public              final                              class                IvoryTower              {              /**    * Private constructor so nobody can instantiate the class.    */                              private                IvoryTower                ()              {}              /**    * Static to class instance of the class.    */              private              static              final              IvoryTower INSTANCE =              new              IvoryTower();              /**    * To be called by user to obtain instance of the class.    *    *                @return                instance of the singleton.    */                              public                static                IvoryTower                getInstance                ()              {              return              INSTANCE;   } }          

The Initialize-on-demand-holder idiom is a secure way of creating a lazy initialized singleton object in Java.

                          package                              com.ramesh.singleton;              public              final                              class                InitializingOnDemandHolderIdiom              {              /**    * Private constructor.    */                              private                InitializingOnDemandHolderIdiom                ()              {}              /**    *                @return                Singleton instance    */                              public                static                InitializingOnDemandHolderIdiom                getInstance                ()              {              return              HelperHolder.INSTANCE;   }              /**    * Provides the lazy-loaded Singleton instance.    */              private              static                              class                HelperHolder              {              private              static              final              InitializingOnDemandHolderIdiom INSTANCE =              new              InitializingOnDemandHolderIdiom();   } }          

5.4 Enum Singleton

To overcome this situation with Reflection, Joshua Bloch suggests the use of Enum to implement a Singleton design pattern as Java ensures that any enum value is instantiated only once in a Java program. Since Java Enum values are globally accessible, so is the singleton. The drawback is that the enum type is somewhat inflexible; for example, it does not allow lazy initialization.

                          package                              com.ramesh.singleton;              /**  * Enum based singleton implementation. Effective Java 2nd Edition (Joshua Bloch) p. 18  */              public              enum              EnumIvoryTower {    INSTANCE;              @Override                              public                String                toString                ()              {              return              getDeclaringClass().getCanonicalName() +              "@"              + hashCode();   } }          

5.5 Test singleton design pattern

                          public                              class                App              {              private              static              final              Logger LOGGER = LoggerFactory.getLogger(App.class);              /**    * Program entry point.    *    *                @param                args command line args    */                              public                static                void                main                (String[] args)              {              // eagerly initialized singleton              IvoryTower ivoryTower1 = IvoryTower.getInstance();     IvoryTower ivoryTower2 = IvoryTower.getInstance();     LOGGER.info("ivoryTower1={}", ivoryTower1);     LOGGER.info("ivoryTower2={}", ivoryTower2);              // lazily initialized singleton              ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower1 =         ThreadSafeLazyLoadedIvoryTower.getInstance();     ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower2 =         ThreadSafeLazyLoadedIvoryTower.getInstance();     LOGGER.info("threadSafeIvoryTower1={}", threadSafeIvoryTower1);     LOGGER.info("threadSafeIvoryTower2={}", threadSafeIvoryTower2);              // enum singleton              EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE;     EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE;     LOGGER.info("enumIvoryTower1={}", enumIvoryTower1);     LOGGER.info("enumIvoryTower2={}", enumIvoryTower2);              // double checked locking              ThreadSafeDoubleCheckLocking dcl1 = ThreadSafeDoubleCheckLocking.getInstance();     LOGGER.info(dcl1.toString());     ThreadSafeDoubleCheckLocking dcl2 = ThreadSafeDoubleCheckLocking.getInstance();     LOGGER.info(dcl2.toString());              // initialize on demand holder idiom              InitializingOnDemandHolderIdiom demandHolderIdiom =         InitializingOnDemandHolderIdiom.getInstance();     LOGGER.info(demandHolderIdiom.toString());     InitializingOnDemandHolderIdiom demandHolderIdiom2 =         InitializingOnDemandHolderIdiom.getInstance();     LOGGER.info(demandHolderIdiom2.toString());   } }          

6. Applicability

Use the Singleton pattern when

  • there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point.
  • when the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code.

6.1 Typical Use Case

Singleton pattern is used for logging , driver objects , caching  and  thread pool . Singleton design pattern is also used in other design patterns like Abstract Factory, Builder, Prototype, Facade  etc.

7. Real world examples

8. Consequences

Violates the Single Responsibility Principle (SRP) by controlling their own creation and lifecycle.

  • Encourages using a global shared instance which prevents an object and resources used by this object from being deallocated.
  • Creates tightly coupled code. The clients of the Singleton become difficult to test.
  • Makes it almost impossible to subclass a Singleton.

9. Credits

  • Design Patterns: Elements of Reusable Object-Oriented Software
  • Effective Java (2nd Edition)

The source code of Singleton pattern on my GitHub repository :

latimerfics1975.blogspot.com

Source: https://www.sourcecodeexamples.net/2017/12/singleton-design-pattern.html

0 Response to "Java Singleton Pattern Example Code"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel