15

Why is Bill Pugh's Singleton design pattern thread safe?

public class Logger {
    private Logger() {
        // private constructor
    }

    // static inner class - inner classes are not loaded until they are
    // referenced.
    private static class LoggerHolder {
        private static Logger logger = new Logger();
    }

    // global access point
    public static Logger getInstance() {
        return LoggerHolder.logger;
    }

    //Other methods
}
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
user9549562
  • 151
  • 1
  • 3
  • Your answer is within comments itself – Nitishkumar Singh Jun 09 '18 at 06:07
  • 1
    Because the semantic for loading and initializing classes is defined in a way that it is only done once and the static final fields are published safely. – eckes Jun 09 '18 at 06:07
  • 3
    Brian Goetz explains this best. You should read his book [Java Concurrency in Practice](http://jcip.net/) for the full explanation. For the abridged version, see this SO question: https://stackoverflow.com/questions/801993/java-multi-threading-safe-publication?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa (But basically, the `static` keyword is special in Java, and implies a *happens-before* edge due to the way Java classes are loaded and initialized.) – markspace Jun 09 '18 at 06:30
  • @AndyTurner Both `final` and `static` do. It's one or the other, it doesn't need to be `final`. Didn't double check but I'm sure that's in Brian Goetz's book. Please check it again! – markspace Jun 09 '18 at 07:25

2 Answers2

5

Lets take a look at the comments:

// static inner class - inner classes are not loaded until they are referenced.

The "loading" is the process of initialising the inner class (LoggerHolder).

"until they are referenced" means the inner class (LoggerHolder) is not initialised until the LoggerHolder.logger static field is referenced ("used somewhere") in this case.

So the call to getInstance() references LoggerHolder.logger and starts the initialisation of the LoggerHolder inner class.

The whole process of initialising a class is synchronised by the JVM.

From the relevant documentation:

Because the Java programming language is multithreaded, initialization of a class or interface requires careful synchronization

The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization

The initialisation of the static field:

private static Logger logger = new Logger();

is a part of the inner class initialisation and this whole initialisation process ("loading") is effectively synchronised by the JVM.

The Bartman
  • 156
  • 2
  • 5
0

I think because of definition of 'static' in java, the inner class and the inner Object (logger in this case) load once with the class loader by jvm.

I think its better to define the logger object as final. Second or other threads cannot instantiate the object again!