简体   繁体   中英

Java Singleton explanation needed

Usually I use the first implementation. Couple of days ago I found another. Can anyone explain me the difference between these 2 implementations ? The 2nd implementation is thread safe? What is the advantage of using inner class in the 2nd example?

//--1st Impl
public class Singleton{

      private static Singleton _INSTANCE;

      private Singleton() {}
      public static Singleton getInstance(){
          if(_INSTANCE == null){
               synchronized(Singleton.class){
                      if(_INSTANCE == null){
                          _INSTANCE = new Singleton();
                      }
               }
          }
      return _INSTANCE;
      }  
}

//--2nd Impl
public class Singleton {
      private Singleton() {}

      private static class SingletonHolder { 
            private static final Singleton _INSTANCE = new Singleton();
      }

      public static Singleton getInstance() {
            return SingletonHolder._INSTANCE;
      }
}

The first implementation uses what is called a "double checked lock". This is a Very Bad Thing. It looks thread-safe, but in fact it is not.

The second implementation is, indeed, thread-safe.

The explanation for why the first implementation is broken is fairly involved, so I'd recommend you get a copy of Brian Goetz's Java Concurrency in Practice for a detailed explanation. The short version is that the compiler is allowed to assign the _INSTANCE variable before the constructor has completed, which can cause a second thread to see a partially-constructed object.

The first implementation is only and only thread-safe if the _INSTANCE is made volatile. The second one is thread safe because the _INSTANCE is only initialized once the SingletonHolder is loaded by the class loader.

So when the inner class is accessed for the time (much later than the whole program was loaded), the class loader loads the inner-class and initializes the variable. So for any later access, the object is readily available Hence the method getInstance() is thread-safe.

The beauty of the second implementation, is you dont have to worry about synchronization or count as class loader does it for you

#1 is designed to ensure lazy initialization. But, in the given case, #2 ensures lazy initialization too. _INSTANCE is created only when Singleton.class is loaded, and Singleton.class is loaded on first invocation of getSingleton(). There is no other method in the class. No double checked locking needed. And of course in #1 _INSTANCE should be volatile.

Note: I do not agree that double checked locking is bad. When implemented correctly it may be very useful.

The first code snippet is an example of the double-checked locking idiom , which used to be quite popular but is now known to be unsafe and should never be used.

The second snippet uses the combination of the semantics of class loading and of the final keyword, as defined by the Java language specification, to ensure lazy initialization and thread safety, so it is much better.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM