Pages

Thursday 30 January 2014

Singleton Pattern in Java



Definition:

The singleton pattern is a 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. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects

  • Ensure that only one instance of a class is created.
  • Provide a global point of access to the object.

UML Diagram:



Implementation:

There are many Implementations of the Singleton pattern in java, lets have a look at all.

1. Using ENUM:


Joshua Bloch explained this approach in his Effective Java Reloaded talk at Google I/O 2008: link to video. Also see slides 30-32 of his presentation (effective_java_reloaded.pdf):


enum Singleton {
 INSTANCE;
 private final String[] favoriteBooks = { "Effective java", "Java Concurrency" };
 public void printFavorites() {
  System.out.println(Arrays.toString(favoriteBooks));
 }
}

According to Joshua Bloch: "This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton."

This implementation will:
  • Work in Multi-threaded environment without synchronizing it.
  • Provides the serialization machinery for free,

2. Lazy Initialization Holder Class/Initialization-on-demand holder idiom


In this technique we create a static class holder  which will return the singleton instance. It uses the Java class initialization guarantee where the static class holder will not get initialized till it is been referenced.This implementation is a well-performing and concurrent implementation valid in all versions of Java.


public class Something implements Serializable {
 private Something() {}
 
 private static class LazyHolder {
  private transient static final Something INSTANCE = new Something();
 }
 
 public static Something getInstance() {
  return LazyHolder.INSTANCE;
 }
 
 protected Object readResolve() {
  return Something.getInstance();
 }
}

  • The static class LazyHolder is only executed when the static method getInstance is invoked on the class Something, and the first time this happens the JVM will load and initialize the LazyHolder class. 
  • It is not sufficient merely to add implements Serializable to its declaration. To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method. Otherwise, each time a serialized instance is deserialized, a new instance will be created.
  • Use this pattern if the initialization of the class is expensive and it cannot be done safely at class-loading time and the initialization is concurrent. .

3. Eager initialization


In the following implementattion the singleton object is instantiated when the class is loaded and not when it is first used, due to the fact that the instance member is declared static. This is why we don't need to synchronize any portion of the code in this case.


public class Singleton implements Serializable {
 private transient static final Singleton instance = new Singleton();

 private Singleton() {}
 public static Singleton getInstance() {
  return instance;
 }
 protected Object readResolve() {
  return instance;
 }
}

4. Lazy initialization


In this implementation the Singleton object is instantiated lazily only when getInstance method is called.

class Singleton implements Serializable {
 private transient static Singleton instance;
 private Singleton() { }
 public static Singleton getInstance() {
  if (instance == null) {
   instance = new Singleton();
  }
  return instance;
 }
 protected Object readResolve() {
  return Singleton.getInstance();
 }
}

  • This implementation will not work in Multi-Threaded environment. Use the below implementation to work with multi threaded environment.

5. Lazy initialization - Synchronized


This is Synchronized version of the Lazy Initialization technique to work in Multi-threaded environment.

class Singleton implements Serializable {
 private transient static Singleton instance;
 private Singleton() { }
 public static synchronized Singleton getInstance() {
  if (instance == null) {
   instance = new Singleton();
  }
  return instance;
 }
 protected Object readResolve() {
  return Singleton.getInstance();
 }
}

Using the synchronized keyword in this way will be extremely costly, because it's acted upon every time the getInstance() method is invoked. There is a different technique to avoid performance bottlenecks in applications, and this is to modify the code to synchronize only the assignment in the getInstance() method.

6. Double-checked locking


Double-checked locking used to reduce the overhead of acquiring a lock by first testing the locking criterion without actually acquiring the lock. Only if the locking criterion check indicates that locking is required does the actual locking logic proceed.


public class Singleton implements Serializable {
 private transient static Singleton instance;
 private Singleton() { }
 public static Singleton getInstance() {
  if(instance == null) {
   synchronized(Singleton.class) {
    if (instance == null) {
     instance = new Singleton();
    }
   }
  }
  return instance;
 }
 protected Object readResolve() {
  return Singleton.getInstance();
 }
}

Applicability & Examples

  • Logger Classes: The Singleton pattern is used in the design of logger classes. This classes are ussualy implemented as a singletons, and provides a global logging access point in all the application components without being necessary to create an object each time a logging operations is performed.
  • Configuration Classes: The Singleton pattern is used to design the classes which provides the configuration settings for an application. By implementing configuration classes as Singleton not only that we provide a global access point, but we also keep the instance we use as a cache object. When the class is instantiated( or when a value is read ) the singleton will keep the values in its internal structure. If the values are read from the database or from files this avoids the reloading the values each time the configuration parameters are used.
  •  Accessing resources in shared mode: It can be used in the design of an application that needs to work with the serial port. Let's say that there are many classes in the application, working in an multi-threading environment, which needs to operate actions on the serial port. In this case a singleton with synchronized methods could be used to be used to manage all the operations on the serial port.
  • Factories implemented as Singletons: Let's assume that we design an application with a factory to generate new objects(Acount, Customer, Site, Address objects) with their ids, in an multithreading environment. If the factory is instantiated twice in 2 different threads then is possible to have 2 overlapping ids for 2 different objects. If we implement the Factory as a singleton we avoid this problem. Combining Abstract Factory or Factory Method and Singleton design patterns is a common practice.

No comments:

Post a Comment