Singleton Pattern   «Prev  Next»
Lesson 13Perfect Singleton Design Pattern
ObjectiveWhat does it take to make the Singleton Design Pattern perfect

Perfect Singleton Design Pattern

The `synchronized` keyword is used in the Singleton Design Pattern to ensure thread safety in multithreaded environments. Here's when and why you should use it:
Why Use `synchronized` in Singleton?**
  1. Thread Safety:
    • In a multithreaded environment, multiple threads might simultaneously attempt to create a Singleton instance. Without synchronization, this can result in multiple instances being created, violating the Singleton's intent.
    • The synchronized keyword ensures that only one thread at a time executes the critical section of code responsible for creating the Singleton instance.
  2. Data Consistency:
    • It prevents threads from accessing or modifying the Singleton's shared instance in an inconsistent state.

When to Use `synchronized`?**
  1. Eager Initialization:
    • No need to use synchronized if the Singleton instance is created at the time of class loading (eager initialization). This approach inherently avoids multithreading issues since the instance is created before any thread accesses it.
          public class Singleton {
            private static final Singleton INSTANCE = new Singleton();
    
            private Singleton() {}
    
            public static Singleton getInstance() {
              return INSTANCE;
            }
          }
        
  2. Lazy Initialization:
    • Use synchronized when the Singleton instance is initialized lazily (i.e., when first accessed). Lazy initialization is prone to race conditions, and synchronization ensures only one instance is created.
          public class Singleton {
            private static Singleton instance;
    
            private Singleton() {}
    
            public static synchronized Singleton getInstance() {
              if (instance == null) {
                instance = new Singleton();
              }
              return instance;
            }
          }
        
  3. Double-Checked Locking for Better Performance:
    • If you want lazy initialization with improved performance, you can use double-checked locking. This reduces the overhead of synchronization by ensuring it only occurs the first time the instance is created.
          public class Singleton {
            private static volatile Singleton instance;
    
            private Singleton() {}
    
            public static Singleton getInstance() {
              if (instance == null) {
                synchronized (Singleton.class) {
                  if (instance == null) {
                    instance = new Singleton();
                  }
                }
              }
              return instance;
            }
          }
        

When Not to Use `synchronized`?**
  1. Single-Threaded Environment:
    • Synchronization is unnecessary in single-threaded applications because thread safety is not a concern.
  2. Eager Initialization:
    • Since the instance is created during class loading, synchronization is redundant.

Key Considerations**
  • Performance:
    • The synchronized keyword can introduce performance overhead due to locking. Use it judiciously, and prefer double-checked locking or eager initialization if performance is critical.
  • Volatile Keyword:
    • When using double-checked locking, declare the instance variable as volatile to prevent issues with instruction reordering.

By understanding your application's requirements and environment, you can decide when to use `synchronized` with the Singleton pattern effectively.

OO Design Principles (Design Patterns)

Given :
11.class ChocolateBoiler { 
12. private static ChocolateBoiler boiler;
13. private ChocolateBoiler() { }
14. public static final ChocolateBoiler getInstance() {
15.  if(boiler == null) {
16.   boiler = new ChocolateBoiler();
17.  }
18.  return boiler;
19.}

The above code shows a class depicting the Singleton design pattern. What can be done to make it a perfect Singleton design pattern?
Please select 1 option:
  1. Remove the if statement on line 15
  2. The given code is already a perfect singleton design pattern.
  3. Mark the static boiler instance variable as final.
  4. Synchronize the getInstance method using synchronized keyword.


Answer : D
Explanation:
In this code fragment, there is a class ChocolateBoiler which has a
  1. static final method getInstance and
  2. a static instance variable boiler.

The default constructor of the ChocolateBoiler class is marked as private. The constructor of this class cannot be called from an outer class because it is private. This prevents the instantiation of the class from an outer class. Hence, only a static method inside the class can access the constructor of the class. The getInstance method serves this purpose and when the getInstance method is invoked, it checks for the boiler variable to be null. If yes, it instantiates the boiler variable, else it returns the object which is already referenced by the boiler variable.
Hence, it is verified that there is one and only one object that is created and returned when asked for. This type of design pattern is called the Singleton design pattern in Java. However, when multithreading comes into the picture, if two or more threads somehow enter the "if block" in the getInstance method, there will be two instances of the ChocolateBoiler which is contradictory to the Singleton pattern. So marking the getInstance method as synchronized ensures thread safety because only one thread will be able to enter the method at a time.
//According to the Oracle docs, the synchronized keyword should appear after the public keyword // https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
class PerfectChocolateBoiler {
 private static PerfectChocolateBoiler boiler;
 private PerfectChocolateBoiler() {	}
 public synchronized static final 
  PerfectChocolateBoiler getInstance() {
  if (boiler == null) {
   boiler = new PerfectChocolateBoiler();
  }
  return boiler;
 }
 public static void main(String[] args) {
  // more code here	 
 }
}

SEMrush Software 13 SEMrush Banner 13