Singleton pattern is a design solution where you can:

  • ensure that only one instance of a class is created;
  • provide a global point of access to the object;
  • allow multiple instances in the future without affecting a singleton class’s clients.

Lazy initialization

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed.

EagerSingleton.java

public class EagerSingleton {

  private static volatile EagerSingleton instance = null;

  public static EagerSingleton getInstance() {

    if (instance == null) {
      synchronized (EagerSingleton.class) {
        if (instance == null) {
          instance = new EagerSingleton();
        }
      }
    }

    return instance;
  }

  // private constructor prevents instantiation from other classes
  private EagerSingleton() {}
}

This method uses double-checked locking, which should not be used prior to J2SE 5.0 as it is vulnerable to subtle bugs.

Eager initialization

If the program will always need an instance, or if the cost of creating the instance is not too large in terms of time/resources, the programmer can switch to eager initialization, which always creates an instance.

EagerSingleton.java

public class EagerSingleton {

  private static volatile EagerSingleton instance = new EagerSingleton();

  public static EagerSingleton getInstance() {
    return instance;
  }

  // private constructor prevents instantiation from other classes
  private EagerSingleton() {}
}

This method has a number of advantages:

  • the instance is not constructed until the class is used;
  • there is no need to synchronize the getInstance() method, meaning all threads will see the same instance and no (expensive) locking is required;
  • the final keyword means that the instance cannot be redefined, ensuring that one (and only one) instance ever exists.

Static block initialization

The static blocks are executed during the loading of class and even before the constructor is called so the programmer can use this feature in the singleton pattern.

StaticBlockSingleton.java

public class StaticBlockSingleton {

  private static final StaticBlockSingleton INSTANCE;

  static {
    try {
      INSTANCE = new StaticBlockSingleton();
    } catch (Exception e) {
      throw new RuntimeException("Unexpected exception!!!...", e);
    }
  }

  public static StaticBlockSingleton getInstance() {
    return INSTANCE;
  }

  // private constructor prevents instantiation from other classes
  private StaticBlockSingleton() {}
}

This method has one drawback. Suppose there are 5 static fields in class and application code needs to access only 2 or 3, for which instance creation is not required at all. So, if we use this static initialization, we will have one instance created though we require it or not.

Bill Pugh solution

Bill Pugh was main force behind java memory model changes. His principle (initialization-on-demand holder idiom) also uses static block but in different way. It suggest to use static inner class.

BillPughSingleton.java

public class BillPughSingleton {

  private static class LazyHolder {
    private static final BillPughSingleton INSTANCE = new BillPughSingleton();
  }

  public static BillPughSingleton getInstance() {
    return LazyHolder.INSTANCE;
  }

  // private constructor prevents instantiation from other classes
  private BillPughSingleton() {}
}

The LazyHolder is loaded on the first execution of BillPughSingleton.getInstance() or the first access to LazyHolder.INSTANCE, not before.

Using Enum

This type of implementation recommend the use of enum. Enum, as written in java docs, provide implicit support for thread safety and only one instance is guaranteed. This is also a good way to have singleton with minimum effort.

EnumSingleton.java

public enum EnumSingleton {

  INSTANCE;

  public void doSomething(String param) {
    // perform operation here 
  }
}

The public method can be written to take any desired types of arguments; a single String argument is used here as an example.

This approach implements the singleton by taking advantage of Java’s guarantee that any enum value is instantiated only once in a Java program. Since Java enum values are globally accessible, so is the singleton, initialized lazily by the classloader. The drawback is that the enum type is somewhat inflexible.


Resources


Categories & Tags


Share