1

Bill pugh solution

public class ThreadSafeSerializedSafeSingleton implements Serializable {

    private ThreadSafeSerializedSafeSingleton() {
    }

    private static class SingletonHelper {
        private static final ThreadSafeSerializedSafeSingleton instance = new ThreadSafeSerializedSafeSingleton();
    }

    public static ThreadSafeSerializedSafeSingleton getInstance() {
        return SingletonHelper.instance;
    }

}

VS

Lazy Initialized Thread Safe Singleton

public class ThreadSafeSingleton {

    private static ThreadSafeSingleton instance;

    private ThreadSafeSingleton() {
    }

    public static synchronized ThreadSafeSingleton getInstance() {
        if (instance == null) {
            instance = new ThreadSafeSingleton();
        }
        return instance;
    }

}
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213

3 Answers3

2

The advantages of Bill Pugh's solution over the presented implementation of lazy initialized singleton are performance related. Consider the next scenario.

The instance is already initialized and two threads concurrently request the instance.

  • For lazy initialized implementation, since the method is synchronized, one of the threads will block.
  • For Bill Pugh implementation there would be no blocking.

Anyway, this could be (partially) mitigated by implemented the singleton via double checked locking. See the example below.

Double Checked locking singleton:

public final class DoubleCheckedLockingSingleton {

    private static volatile DoubleCheckedLockingSingleton instance;

    private DoubleCheckedLockingSingleton(){
        if(instance!=null)
            throw new RuntimeException();
    }

    public static final DoubleCheckedLockingSingleton getInstance(){
        if(instance==null){
            synchronized(DoubleCheckedLockingSingleton.class) {
                if(instance==null)
                    instance = new DoubleCheckedLockingSingleton();
            }
        }
        return instance;
    }

}

In this case, the performance difference is insignificant. The main difference between a double checked locking implementation and a holder pattern implementation is the reason why it works.

  • Double checked locking: threads will block only if they trigger the instance creation concurrently. You have to recheck for instance == null inside the synchronized block since two threads could (potentially although highly unlikely - the best kind of bug) swap out between the first if and the synchronized block. You also have to declare the variable volatile in order to leverage the JMM 'happens before' guarantees of volatile (so you are sure the instance==null check won't return false until the instance is fully initialized).
  • Holder pattern: threads will block only if they trigger the instance creation concurrently. All you have to know is that classes in Java are loaded lazily, with lock from JVM (so both locking and visibility are enforced out of the box, with no additional effort from your side).

Personally, I prefer holder pattern over double checked locking since the reasons why it works seem easier to understand (at lest to me).

As a final note, if your requirements allows it (i.e. if you are using a DI framework, such as Spring), the best way to implement a singleton would be to let Spring provide the singleton for you (by using @Component with the default singleton scope).

  • 1
    Well! In that case what is the advantage of Bill pugh solution over Double checked locking solution? – Mazin Ismail Sep 18 '18 at 08:27
  • 1
    It is considerably easier to write a badly implemented singleton using double checked locking (by forgetting to check again for instance == null in the synchronized block or by forgetting to declare the instance volatile) than it is to write it badly using holder idiom. Holder idiom makes it harder for the programmer to screw up. Besides that, I am not aware of any advantage :). –  Sep 18 '18 at 08:30
1

This is actually called the "holder" pattern.

Its advantages are outlined here:

Initialization of the static helper field is deferred until the getInstance() method is called. The necessary happens-before relationships are created by the combination of the class loader's actions loading and initializing the Holder instance and the guarantees provided by the Java memory model (JMM). This idiom is a better choice than the double-checked locking idiom for lazily initializing static fields [Bloch 2008]. However, this idiom cannot be used to lazily initialize instance fields [Bloch 2001].

The "real" answer here: there are many solutions to the "double checked locking" problem, and they all have slightly different pros/cons.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
0

The obvious advantage is clearly that there is no synchronisation in the Bill Pugh method.

There is a third option which I usually use in the enum method but that is just a personal preference.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213