Double checked locking pattern: Broken or not?
Asked Answered
I

7

9

Why is the pattern considered broken? It looks fine to me? Any ideas?

public static Singleton getInst() {
    if (instace == null) createInst();
    return instace;
}

private static synchronized createInst() {
     if (instace == null) {
         instace = new Singleton(); 
     }
}
Insurrectionary answered 1/9, 2010 at 9:48 Comment(4)
You could avoid this problem altogether by using a DI/IOC container and allowing the container to control the lifetime of the object rather than embedding such logic into the object itself....Not an answer but something to think about.Arabel
Does the code posted here in the question even count as an example of double-checked locking? The lock is being checked once.Niblick
see #3579104Hypogenous
@matt i see if(instance==null) twice hereHickie
L
22

It looks okay at first glance, but this technique has many subtle problems and should usually be avoided. For example, consider the following sequence of events:

  1. Thread A notices that the value is not initialized, so it obtains the lock and begins to initialize the value.
  2. The code generated by the compiler is allowed to update the shared variable to point to a partially constructed object before A has finished performing the initialization.
  3. Thread B notices that the shared variable has been initialized (or so it appears), and returns its value. Because thread B believes the value is already initialized, it does not acquire the lock. If B uses the object before all of the initialization done by A is seen by B the program will likely crash.

You could avoid this by using the "volatile" keyword to handle your singleton instances correctly

Lobotomy answered 1/9, 2010 at 10:5 Comment(3)
+1 - The only answer that points the double-checked locking pattern problem in Java!!Schismatic
Volatile still brings in a few problems, have a look at my answer.Hickie
Neither volatile or lazy loading is the correct approach, instead use a static initializerNiblick
S
11

The whole discussion is a huge, endless waste of brain time. 99.9% of the time, singletons do not have any significant setup costs and there is no reason whatsoever for contrived setups to achieve non-synchronized guaranteed-lazy loading.

This is how you write a Singleton in Java:

public class Singleton{
    private Singleton instance = new Singleton();
    private Singleton(){ ... }
    public Singleton getInstance(){ return instance; }
}

Better yet, make it an enum:

public enum Singleton{
    INSTANCE;
    private Singleton(){ ... }
}
Silicle answered 1/9, 2010 at 10:39 Comment(3)
you probably also want to make the class final (although a private constructor goes in that direction)Spurtle
+1, double checked locking is the mother of all premature nanooptimzationsSulfurous
For the enum constructor, private is redundant. Compiler will make it private. It is written down in the specification: "In an enum declaration, a constructor declaration with no access modifiers is private." See docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.9.2Darbee
D
7

I don't know if it is broken, however it is not really the most efficient solution due to synchronizing which is rather expensive. A better approach would be using the 'Initialization On Demand Holder Idiom', which loads your singleton in memory the first time it is demanded, as the name implies, thus lazy loading. The biggest benefit you get with this idiom is that you don't need to synchronize because the JLS ensures that class loading is serial.

Detailed wikipedia entry on the subject: http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

Another thing to keep in mind is that since dependency injection frameworks such as Spring and Guice have emerged, class instances are being created created and managed by these containers and they will provide you with a Singleton if desired, so it is not worth breaking your head over it, unless you want to learn to idea behind the pattern, which is useful. Also note that singletons provided by these IOC containers are singletons per container instance, but typically you'll have one IOC container per application, so it doesn't become an issue.

Diagnostician answered 1/9, 2010 at 9:59 Comment(2)
Only creation of the instance is synchronizedLobotomy
Nice idiom. (Anyway the question remains unanswered). I should add that synch is less costly with newer JVM's.Schismatic
H
6

The problem is the following: Your JVM may reorder your code and fields are not always the same for different threads. Have a look at this: http://www.ibm.com/developerworks/java/library/j-dcl.html. The use of the volatile keyword should fix this, but its broken before java 1.5.

Most of the time single checked locking is more than fast enough, try this:

// single checked locking: working implementation, but slower because it syncs all the time
public static synchronized Singleton getInst() {
    if (instance == null) 
        instance = new Singleton();
    return instance;
}

Also have a look at effective java, where you will find a great chapter about this topic.

To sum this up: Dont do double checked locking, there are better idoms.

Hickie answered 1/9, 2010 at 10:28 Comment(0)
S
4

Initialization On Demand Holder Idiom, yup that's it:

public final class SingletonBean{

    public static SingletonBean getInstance(){
        return InstanceHolder.INSTANCE;
    }

    private SingletonBean(){}

    private static final class InstanceHolder{
        public static final SingletonBean INSTANCE = new SingletonBean();
    }

}

Although Joshua Bloch also recommends the Enum singleton pattern in Effective Java Chapter 2, Item 3:

// Enum singleton - the prefered approach
public enum Elvis{
    INSTANCE;
    public void leaveTheBuilding(){ ... }
}
Spurtle answered 1/9, 2010 at 10:6 Comment(0)
A
2

This does not answer your question (others already have done), but I want to tell you my experience with singletons/lazy initialized objects:

We had a couple of singletons in our code. Once we had to add a constructor parameter to one singleton and had a serious problem, because the constructor of this singleton was invoked on the getter. There were only following possible solutions:

  • provide a static getter (or another singleton) for the object which was needed to initialize this singleton,
  • pass the object to initialize the singleton as parameter for the getter or
  • get rid of the singleton by passing instances around.

Finally, the last option was the way to go. Now we initialize all objects at application start and pass required instances around (maybe as a small interface). We have not regretted this decision, because

  • the dependencies of a piece of code is crystal clear,
  • we can test our code much easier by providing dummy implementations of the required objects.
Aerograph answered 1/9, 2010 at 10:44 Comment(1)
The Singleton pattern is indeed over-used and oftentimes a sign of poor designNiblick
N
2

Most of the answers here are correct about why it is broken, but are incorrect or suggesting dubious strategies for a solution.

If you really, really must use a singleton (which in most cases you should not, as it destroys testability, combines logic about how to construct a class with the class's behavior, litters the classes that use the singleton with knowledge of how to get one, and leads to more brittle code) and are concerned about synchronization, the correct solution is to use a static initializer to instantiate the instance.

private static Singleton instance = createInst();

public static Singleton getInst() {
    return instance ;
}

private static synchronized createInst() {
    return new Singleton(); 
}

The Java language specification guarantees that static initiailzers will be run just once, when a class is loaded for the first time, and in a guaranteed thread-safe manner.

Niblick answered 1/9, 2010 at 13:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.