Java Singleton and Synchronization
Asked Answered
W

8

135

Please clarify my queries regarding Singleton and Multithreading:

  • What is the best way to implement Singleton in Java, in a multithreaded environment?
  • What happens when multiple threads try to access getInstance() method at the same time?
  • Can we make singleton's getInstance() synchronized?
  • Is synchronization really needed, when using Singleton classes?
Washroom answered 23/6, 2012 at 0:47 Comment(0)
B
238

Yes, it is necessary. There are several methods you can use to achieve thread safety with lazy initialization:

Draconian synchronization:

private static YourObject instance;

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

This solution requires that every thread be synchronized when in reality only the first few need to be.

Double check synchronization:

private static final Object lock = new Object();
private static volatile YourObject instance;

public static YourObject getInstance() {
    YourObject r = instance;
    if (r == null) {
        synchronized (lock) {    // While we were waiting for the lock, another 
            r = instance;        // thread may have instantiated the object.
            if (r == null) {  
                r = new YourObject();
                instance = r;
            }
        }
    }
    return r;
}

This solution ensures that only the first few threads that try to acquire your singleton have to go through the process of acquiring the lock.

Initialization on Demand:

private static class InstanceHolder {
    private static final YourObject instance = new YourObject();
}

public static YourObject getInstance() {
    return InstanceHolder.instance;
}

This solution takes advantage of the Java memory model's guarantees about class initialization to ensure thread safety. Each class can only be loaded once, and it will only be loaded when it is needed. That means that the first time getInstance is called, InstanceHolder will be loaded and instance will be created, and since this is controlled by ClassLoaders, no additional synchronization is necessary.

Bebop answered 23/6, 2012 at 1:1 Comment(39)
Warning - be careful with double-checked synchronization. It doesn't work properly with pre-Java 5 JVMs due to "issues" with the memory model.Saiff
-1 Draconian synchronization and Double check synchronization getInstance()-method must be static!Sino
@PeterRader They don't need to be static, but it might make more sense if they were. Amended as requested.Bebop
@PeterRader The same pattern would be used for any object that needs thread safe lazy instantiation.Bebop
What about notifyAll() on the lock??Leontineleontyne
@powerX Why would I need to worry about that? I am never calling wait on the lock.Bebop
Ah, I'm assumed wrong that other threads are waiting when they are getting to the synchronized(lock), and that notifyAll() is the this that is waking them.Leontineleontyne
What are the disadvantages of the last method? or, what are the advantages of the others over it?Thresathresh
@androiddeveloper The advantage of the last method is its simplicity. Its disadvantage is that you have to make a separate class. You will have an extra *.class file and class loading is also not a free operation.Bebop
@Bebop but you can just put it all in the same class, and then I can't find any disadvantage. it's on demand, thread safe, very fast, very easy,...Thresathresh
@androiddeveloper In order for initialization on demand to work, the holder must be a separate static inner class, otherwise it will not work. This will generate another *.class file at compilation time, and a class loading overhead when you first access your singleton.Bebop
@Bebop I meant the one called "Eager initialization" on wikipedia here: en.wikipedia.org/wiki/Singleton_patternThresathresh
@androiddeveloper Ah. All of the examples in my answer use lazy evaluation (the opposite is eager evaluation). Lazy evaluation can be more efficient in the situation where you might not need to use the singleton.Bebop
@Bebop But if you won't use the singleton, you won't reach the code and the instance won't be created, so it's a win-win, no? The way I remember it is that as soon as you reach the singleton class (a bit before the real call to getInstance) , the static reference is filled with the new instance.Thresathresh
@androiddeveloper Sometimes the singleton pattern is implemented as a part of a larger more complex object. Let's say an object has two main tasks: the first task which is unrelated to the singleton, and the second task. If you use an object for only the first task while using eager initialization, you will waste time and resources creating the singleton which you will not use.Bebop
@Bebop but in both cases you will need to instantiate it and waste time and resources, since you need to perform the task...Thresathresh
@androiddeveloper There are some cases where it is not a guarantee that you want to use the resource. Or maybe you want to delay instantiating the resource until when you need it so that you have a faster start up time.Bebop
@Bebop But if you don't use it, why call it? right when you start using it, it will get instantiated.Thresathresh
this may be a stupid question, but where does your lock object come from?Ashkhabad
You're implementation of double checked locking isn't guaranteed to work. It's actually explained in the article you cited for double checked locking. :) There is an example in there using volatile that works properly for 1.5 and higher (double checked locking is just plain broken below 1.5). The initialization on demand holder also cited in the article would probably be a simpler solution in your answer.Wailoo
@Wailoo I'm aware. However, I have yet to run into a single instance where I was running on anything before Java 1.6, so it's safe to say that it will work correctly.Bebop
I think this lock object is unnecessary. Why not synchronize on the YourObject.class itself.?Insurer
@Vito because anyone can synchronize on YourObject.class. It's always safer to use a private lock object because then you know exactly when and where the monitor will be grabbedBebop
why InstanceHolder must be a separate class? public class Foo { private static Foo f = new Foo(); public static Foo getInstance() {return f;} What's wrong with this?Zarzuela
@Zarzuela That will work for eagerly initialized singletons, but if you want a lazily loaded singleton you'll probably want to use Initialization on DemandBebop
Why do we need 'r'? Why can we just use - public static YourObject getInstance() { if (instance == null) { synchronized (lock) { if (instance == null) { instance = new YourObject(); } } } return instance; } Please excuse the formatting. What I have typed above is the one in the answer by Dan MoldovanSeverally
@Severally AFAIK, r is not needed for correctness. It's just an optimization to avoid accessing the volatile field, since that's far more expensive than accessing a local variable.Bebop
Doesn't the synchronized block ensure that the non-cached values of the fields will be retrieved, meaning that the volatile part is not needed anymore ? Is this still required even today?Thresathresh
@androiddeveloper Entering a synchronized block is more expensive than accessing a volatile variable. Making the variable volatile means we get to skip entering the synchronized block at all after the singleton has been initialized.Bebop
@Bebop So the volatile is only good for performance of first access , and not for better thread-safety as I've read on some places? Also, isn't this a relatively tiny boost, as it's only for current threads, and only for the case that they are before the synchronized part and it's being updated now? Meaning it's a very specific thing, no?Thresathresh
@androiddeveloper I'd recommend reading through the wiki page I linked to above if you want all the nitty gritty details. We need volatile to ensure thread safety/memory consistency. It's good for performance for all accesses after the singleton has been initialized. It is not a tiny boost.Bebop
@Bebop But then it's not only for performance, no?Thresathresh
@androiddeveloper You could have a solution that always synchronized. That solution would be correct, but pretty slow. We use volatile to improve the performance of a such a solution while ensuring thread safety.Bebop
@Bebop I understand, but with the double check, is it indeed needed to use volatile for thread safety ? I wonder if using AtomicReference is also the sameThresathresh
If the singleton initialization needs to eventually call a web service or fetch from a database, where do you place this code? Do you put it inside the singleton class or outside? Can you please point me to examples.Renae
@Renae that opens up a whole other can of worms: How do you handle retries? If your singleton initialization logic could fail, you need to handle the case where it will fail. Potentially permanently. I don't know of any simple examples I can point you to, but I know some server frameworks have systems where you can tell it to retry initializing your singleton until it succeeds, and it won't start your server until it does. And if this isn't a server use case, you can accomplish something similar yourself by writing that retry loop before executing the CLI command.Bebop
I have already developed the retry logic and embedded it along with the singleton initialization and web service invocation. Check my recent questions.Renae
what is the importance of a null check when the call is already synchronized in Draconian synchronization?Whelk
@Whelk You typically only want to initialize singletons exactly once. Otherwise, why bother with a singleton at all? You could just create a new object every time you needed its functionality.Bebop
C
84

This pattern does a thread-safe lazy-initialization of the instance without explicit synchronization!

public class MySingleton {

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

     private MySingleton () {}

     public static MySingleton getInstance() {
         return Loader.INSTANCE;
     }
}

It works because it uses the class loader to do all the synchronization for you for free: The class MySingleton.Loader is first accessed inside the getInstance() method, so the Loader class loads when getInstance() is called for the first time. Further, the class loader guarantees that all static initialization is complete before you get access to the class - that's what gives you thread-safety.

It's like magic.

It's actually very similar to the enum pattern of Jhurtado, but I find the enum pattern an abuse of the enum concept (although it does work)

Calcariferous answered 23/6, 2012 at 1:9 Comment(14)
Synchronization is still present, it's just enforced by the JVM instead of by the programmer.Bebop
@Bebop You're right of course - I was typing it all in (see edits)Calcariferous
Why not add an explicit "final" qualifier to the declaration of INSTANCE? Took me a while to sort it out without it.Jijib
@ТаняТ. There's nothing to sort out. It's a private class so nothing else has access to it and it's initialized statically. Make it final if you want, but it won't make any difference to the safety or behaviour.Calcariferous
I understand it makes no difference to the JVM, I am just saying it made a difference to me as far as self-documented code goes. I've just never seen all caps in Java without the "final" keyword before (or enum), got a bit of cognitive dissonance. For someone programming Java full time, it probably would not make a difference, but if you jump languages back and forth, it helps to be explicit. Ditto for newbies. Although, I am sure one can adapt to this style pretty quick; all caps is probably enough. Don't mean to nit pick, I liked your post.Jijib
Excellent answer, though I didn't get some part of it. Can you elaborate "Further, the class loader guarantees that all static initialization is complete before you get access to the class - that's what gives you thread-safety." , how that helps in thread safety, I'm a little confused about that.Pentomic
Why not static final MySingleton INSTANCE?Regressive
@Regressive actually, although it's not necessary, I agree for style reasons (since it is effectively final because no other code can access it) final should be added. Done.Calcariferous
How would I pass an argument to the MySingleton constructor inside the inner class if the getInstance method requires a parameter?Golconda
@Golconda do you want public static MySingleton getInstance(Object param) {...}?Calcariferous
Yes. How would I pass param to MySingleton if the constructor requires param?Golconda
@robur will the parameter be the same for all calls? If not, should a different instance be returned for each distinct parameter value? Or, if the parameter is effectively a constant, can it be known when the class is loaded? I need a lot more detail about the parameter value, its influence and lifecycle in order to answer your question (and depending on your clarification, may be more appropriate to ask In its own separate question)Calcariferous
@Calcariferous Why is this impl. called lazy initialization when JVM is going to do it? I thought lazy meant when an instance is not created apriori.Phenomena
@Phenomena “lazy” means “left until actually needed for use”. This specific code pattern has a name: Initialization-on-demand holder idiom. Read that article for a more complete explanation.Calcariferous
D
23

If you are working on a multithreaded environment in Java and need to gurantee all those threads are accessing a single instance of a class you can use an Enum. This will have the added advantage of helping you handle serialization.

public enum Singleton {
    SINGLE;
    public void myMethod(){  
    }
}

and then just have your threads use your instance like:

Singleton.SINGLE.myMethod();
Dampier answered 23/6, 2012 at 1:1 Comment(0)
C
10

Yes, you need to make getInstance() synchronized. If it's not there might arise a situation where multiple instances of the class can be made.

Consider the case where you have two threads that call getInstance() at the same time. Now imagine T1 executes just past the instance == null check, and then T2 runs. At this point in time the instance is not created or set, so T2 will pass the check and create the instance. Now imagine that execution switches back to T1. Now the singleton is created, but T1 has already done the check! It will proceed to make the object again! Making getInstance() synchronized prevents this problem.

There a few ways to make singletons thread-safe, but making getInstance() synchronized is probably the simplest.

Cheeseparing answered 23/6, 2012 at 0:49 Comment(2)
Will it help by putting object creation code in Synchronized block, instead of making entire method synchronization?Washroom
@RaoG No. You want both the check and the creation in the synchronization block. You need those two operations happen together without interruptions or the situation I described above may happen.Cheeseparing
F
8

Enum singleton

The simplest way to implement a Singleton that is thread-safe is using an Enum

public enum SingletonEnum {
  INSTANCE;
  public void doSomething(){
    System.out.println("This is a singleton");
  }
}

This code works since the introduction of Enum in Java 1.5

Double checked locking

If you want to code a “classic” singleton that works in a multithreaded environment (starting from Java 1.5) you should use this one.

public class Singleton {

  private static volatile Singleton instance = null;

  private Singleton() {
  }

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

This is not thread-safe before 1.5 because the implementation of the volatile keyword was different.

Early loading Singleton (works even before Java 1.5)

This implementation instantiates the singleton when the class is loaded and provides thread safety.

public class Singleton {

  private static final Singleton instance = new Singleton();

  private Singleton() {
  }

  public static Singleton getInstance() {
    return instance;
  }

  public void doSomething(){
    System.out.println("This is a singleton");
  }

}
Faithfaithful answered 2/10, 2015 at 11:35 Comment(0)
T
2

You can also use static code block to instantiate the instance at class load and prevent the thread synchronization issues.

public class MySingleton {

  private static final MySingleton instance;

  static {
     instance = new MySingleton();
  }

  private MySingleton() {
  }

  public static MySingleton getInstance() {
    return instance;
  }

}
Tippett answered 12/6, 2014 at 18:44 Comment(3)
@Vimsha A couple other things. 1. You should make instance final 2. You should make getInstance() static.Dilantin
What would you do if you want to create a thread in the singleton.Equivoque
@arun-george use a thread pool, a single thread pool if needed, and surround with a while(true)-try-catch-throwable if you want to ensure your thread never dies, no matter what error?Brisco
A
0

What is the best way to implement Singleton in Java, in a multithreaded environment?

Refer to this post for best way to implement Singleton.

What is an efficient way to implement a singleton pattern in Java?

What happens when multiple threads try to access getInstance() method at the same time?

It depends on the way you have implemented the method.If you use double locking without volatile variable, you may get partially constructed Singleton object.

Refer to this question for more details:

Why is volatile used in this example of double checked locking

Can we make singleton's getInstance() synchronized?

Is synchronization really needed, when using Singleton classes?

Not required if you implement the Singleton in below ways

  1. static intitalization
  2. enum
  3. LazyInitalaization with Initialization-on-demand_holder_idiom

Refer to this question fore more details

Java Singleton Design Pattern : Questions

Alexaalexander answered 27/6, 2016 at 9:30 Comment(0)
R
0
public class Elvis { 
   public static final Elvis INSTANCE = new Elvis();
   private Elvis () {...}
 }

Source : Effective Java -> Item 2

It suggests to use it, if you are sure that class will always remain singleton.

Reckoning answered 2/1, 2017 at 22:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.