6

How does Singleton behave when two threads call the "getInstance()" at the same time? What are the best practices to protect it?

xpollcon
  • 525
  • 1
  • 6
  • 9
  • Use an `enum` to implement your Singleton. – Elliott Frisch Jan 05 '14 at 23:44
  • 3
    Or, better yet, don't implement it at all. :P There's hardly ever a good reason for a capital-S Singleton, but plenty of bad/misguided ones. – cHao Jan 05 '14 at 23:45
  • possible duplicate of [What is an efficient way to implement a singleton pattern in Java?](http://stackoverflow.com/questions/70689/what-is-an-efficient-way-to-implement-a-singleton-pattern-in-java) – assylias Jan 06 '14 at 00:16
  • This is not a duplicate. @xpollcon asks e.g. if the 2nd thread will block or not when the 1st thread calls the singleton's method. – Mike Argyriou Oct 24 '15 at 11:00

5 Answers5

4

This is only an issue at all if you use lazy initialization on the singleton. If you use eager initialization then the JVM guarantees to sort it all out for you.

For lazy initialization you need to either synchronize (although you can make it volatile and use double-check locking to avoid synchronized blocks all the time) or embed it within an inner class where it is not lazy initialized.

peter.petrov's answer now covers most of the options well, there is one final approach to thread safe lazy initialization though that is not covered and it is probably the neatest one.

public class Singleton {

  // Prevent anyone else creating me as I'm a singleton
  private Singleton() {
  }

  // Hold the reference to the singleton instance inside a static inner class
  private static class SingletonHolder {
    static Singleton instance = new Singleton();    
  }

  // Return the reference from inside the inner class
  public static Singleton getInstance() {
    return SingletonHolder.instance;
  }

}

Java does lazy loading on classes, they are only loaded when first accessed. This applies to inner classes too...

Tim B
  • 40,716
  • 16
  • 83
  • 128
  • I thought double-checked locking is broken. At least I read such an article long long ago. http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html – peter.petrov Jan 05 '14 at 23:46
  • I think it was fixed in Java 5 or 6. From what I recall, if you mark your instance volatile and lock when creating it, you should be fine. Better yet, don't do lazy init or try to avoid singletons all together. Edit: here is a good discussion on it: http://stackoverflow.com/questions/7855700/why-is-volatile-used-in-this-example-of-double-checked-locking – Todd Jan 05 '14 at 23:48
  • @Todd I see. Can you point me to some reference saying it was fixed and describing the recommended way of doing lazy init using that fix? Would be good for me to learn something new ;) – peter.petrov Jan 05 '14 at 23:50
  • @peter.petrov: only if you do it wrong. See following article with false fixes and the right way to do it: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – Christian Strempfer Jan 05 '14 at 23:52
  • @peter.petrov DCL is fine with Java 5+ as long as the variable is volatile. – assylias Jan 06 '14 at 00:14
  • @assylias Right, got it. Updated my answer with the new stuff just learned ;) – peter.petrov Jan 06 '14 at 00:31
3

Firstly, two threads can't call the method at the "same time" - one will be deemed to call it first... called a "race condition".

Next, any properly implemented singleton will handle a race condition cleanly. IMHO, this is the cleanest way to implement a thread-safe singleton without synchronization:

public class MySingleton {
    private static class Holder {
        static final MySingleton INSTANCE = new MySingleton ();
    }

    public static MySingleton getInstance() {
        return Holder.INSTANCE;
    }
    // rest of class omitted
}

This is called the initialization-on-demand holder idiom.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • +1 I've seen this pattern somewhere. Very nice and simple. So the race condition is eliminated by the class loading of Holder, right? – peter.petrov Jan 05 '14 at 23:57
  • Never mind, yes, it's mentioned in the link you provided. OK. – peter.petrov Jan 06 '14 at 00:00
  • there is synchronizion (there has to be to handle race conditions) but it's invisible - it is built in to the class loader. – Bohemian Jan 06 '14 at 00:11
  • I've always struggled to find the reason not to use `public enum MySingleton { INSTANCE; }` vs this idiom. The only difference is that with the enum, the singleton is loaded when the enum is loaded vs. the singleton is loaded when `getInstance` is called with the private holder. However I don't see why you would load the enum unless you plan to actually use the singleton, so in most reasonable cases they would be loaded at the same time... – assylias Jan 06 '14 at 00:29
  • 1
    @assylias I find the enum pattern too contrived (not denying it works and is solid). What I don't like about enum is it's *not* really an enum. Good point about instantiation timing, but I don't think of a case where you would access the enum class without touching the instance. You could I suppose use an private enum instead of a holder sitting behind a static getter, but why bother. – Bohemian Jan 06 '14 at 01:40
  • Doh, I just read the discussion on my answer and posted essentially this - then saw you had already done it. Oh well :) – Tim B Jan 06 '14 at 09:26
2

1) If you want lazy init, I think a good practice is to synchronize the getInstance body on a private static final Object instance which is member of the same class (you may name it LOCK e.g.).

2) If you don't need lazy init you can just instantiate your singleton instance at class load time. Then there's no need of any synchronization in getInstance.

Sample of 1) without using DCL (double-checked locking)

Note 1: This one avoids the complexity of using DCL by paying some extra price with respect to performance.
Note 2: This version is OK on JDK < 5 as well as on JDK >= 5.

public class Singleton {

    private static final Object LOCK = new Object();
    private static Singleton instance = null;

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

    private Singleton(){
        // code to init this
    }


}

Sample of 1) using DCL

Note 1: This is OK on JDK >= 5 but not on JDK < 5.
Note 2: Note the volatile keyword used, this is important.

public class Singleton {

    private static final Object LOCK = new Object();
    private static volatile Singleton instance = null;

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

    private Singleton(){
        // code to init this
    }


}

Sample of 2)

Note 1: This is the most simple version.
Note 2: Works on any JDK version.

public class Singleton {

    private static Singleton instance = new Singleton();

    public static Singleton getInstance(){
        return instance;
    }

    private Singleton(){
        // code to init this
    }

}

References:

1) Older JDK versions (JDK < 5)
http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html

2) More recent updates on DCL
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

peter.petrov
  • 38,363
  • 16
  • 94
  • 159
1
public class Singleton{

      private static class Holder {
          static final Singleton INSTANCE = new Singleton();
      }

      public static Singleton getInstance() {
          return Holder.INSTANCE;
      }

} 

When the getInstance method is invoked for the first time, it reads Holder.INSTANCE for the first time, causing the Holder class to get initialized. The beauty of this idiom is that the getInstance method is not synchronized and performs only a field access.This is called lazy initialization. You might think that Holder class should also be loaded by the class loader when Singleton class is loaded because Holder class is static. Loading a top-level class does not automatically load any nested types within,Unless there's some other initialization that occurs during the top-level initialization, like if your top-level class has a static field that needs to be initialized with a reference to an instance of the nested class.

indika
  • 821
  • 7
  • 13
0

Synchronize access of getInstance.

Class TestSingleton {

  private static volatile TestSingleton singletonObj = null;   

  private TestSingleton (){    // make constructor private
  }

  public static getInstance(){
       TestSingleton obj = singletonObj ;
       if(obj == null) {
       synchronized(lock) {    // while we were waiting for the lock, another 
             obj = instance;       // thread may have instantiated the object
             if(obj == null) {  
                obj = new TestSingleton();
                instance = obj ;
             }
        }
   }
  public doSomeWork(){    // implementation
  }

}

Vivek Vermani
  • 1,934
  • 18
  • 45