Tuesday, September 7, 2010

Lazy initialization of Java Singletons

Code snippet below shows a typical way of initializing singleton class in Java.

class Singleton {
  private static Singleton singleton;

  private Singleton() {
  }

  public static synchronized Singleton getSingleton() {
      if (singleton == null)
          singleton = new Singleton();
      return singleton;
  }
}


Nothing wrong with this approach but the only issue is performance penalty we pay for the synchronized block. Another not so clean way to get around this is by using Double-checked locking idiom as shown below in the code snippet. But again volatile variables are not terribly fast as compared to synchronized blocks so the performance mileage we get out this, won't be much.

class Singleton {
  private volatile static Singleton singleton;

  private Singleton() {
  }

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

Fortunately, there is a better and cleaner way of doing this by using Initialization on Demand Holder Idiom.
...
static class SingletonHolder {
  private static Singleton singleton = new Singleton();

  public static Singleton getSingleton() {
      return singleton;
  }
}
...

The trick here is that whenever the first call to SingletonHolder.getSingleton() is made, the SingletonHolder static class will be loaded into the JVM and so, JVM will take care of synchronizing if multiple threads are invoking the method and hence it is obviously going to be more efficient than users doing synchronization.

1 comment:

  1. In the demand holder idiom, lazy initialization no longer holds good. The singleton will be instantiated at class-loading time - hence it will be loaded as soon as the class is loaded by the VM.

    Secondly, using volatile will provide a performance gain in this case, as we do not require an atomic read-update-write operation. It will be a "write-once" and always-read operation in this scenario. There is no locking involved on the volatile variables which will help performance.

    For best performance, and to avoid the "synchronized (Singleton.class)" block, the following should be used:

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
    }....

    ReplyDelete