14

I understand that double locking in Java is broken, so what are the best ways to make Singletons Thread Safe in Java? The first thing that springs to my mind is:

class Singleton{
    private static Singleton instance;

    private Singleton(){}

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

Does this work? if so, is it the best way (I guess that depends on circumstances, so stating when a particular technique is best, would be useful)

Robert
  • 8,406
  • 9
  • 38
  • 57
  • change `return new Singleton()` to `instance = new Singleton()` – aioobe May 26 '10 at 11:07
  • oops, well spotted! Wrote without testing... – Robert May 26 '10 at 11:11
  • 5
    Can someone tell me why people are so concerned with lazy initialization of Singletons? The usage pattern for them is, using this example: `Singleton.getInstance( )`. In 99% of cases there should be no other reasons to load Singleton class without calling its `getInstance` method. If the `instance` is `static final` then it will be initialized when Singleton class is loaded, period, and will be thread safe. While `LazyHolder` pattern does work I think it's unnecessary overkill and an anti-pattern, as well as singleton is anti-pattern itself. – Alexander Pogrebnyak May 26 '10 at 11:43
  • Surely, if it creation is expensive there would be times when building on load is too costly, as the object will stay on the heap even if it is never used. – Robert May 26 '10 at 11:57
  • @Robert. That's the point. The only reason to load singleton class is to call `getInstance` right away. Without this call there is absolutely no need to load a singleton class. – Alexander Pogrebnyak May 26 '10 at 12:06
  • @Alexander The class may be loaded, even if no instance is ever created. The lazy initialization is there to defer/prevent that. – DJClayworth May 26 '10 at 13:10

5 Answers5

26

Josh Bloch recommends using a single-element enum type to implement singletons (see Effective Java 2nd Edition, Item 3: Enforce the singleton property with a private constructor or an enum type).

Some people think this is a hack, since it doesn't clearly convey intent, but it does work.

The following example is taken straight from the book.

public enum Elvis {
   INSTANCE;

   public void leaveTheBuilding() { ... }
}

Here is his closing arguments:

This approach [...] is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiations, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.


On enum constant singleton guarantee

JLS 8.9. Enums

An enum type has no instances other than those defined by its enum constants. It is a compile-time error to attempt to explicitly instantiate an enum type (§15.9.1).

The final clone method in Enum ensures that enum constants can never be cloned, and the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization. Reflective instantiation of enum types is prohibited. Together, these four things ensure that no instances of an enum type exist beyond those defined by the enum constants.


On lazy initialization

The following snippet:

public class LazyElvis {
    enum Elvis {
        THE_ONE;
        Elvis() {
            System.out.println("I'M STILL ALIVE!!!");
        }       
    }
    public static void main(String[] args) {
        System.out.println("La-dee-daaa...");
        System.out.println(Elvis.THE_ONE);
    }
}

Produces the following output:

La-dee-daaa...
I'M STILL ALIVE!!!
THE_ONE

As you can see, THE_ONE constant is not instantiated through the constructor until the first time it's accessed.

Community
  • 1
  • 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • Does the client have specific control of when the singleton is initialized? – aioobe May 26 '10 at 11:11
  • @Robert I think that, because Elvis is an inner-class, Elvis.THE_ONE is not instantiated until it is called. I think this is a special property of inner-classes...if Elvis were a "regular" outer-class, then Elvis.THE_ONE would be instantiated as soon as the application started. Someone please correct me if I'm wrong. – Michael May 26 '10 at 16:01
  • @mangst: I did some experimentation, and actually my test above is not conclusive at all, and may in fact be misleading. Enum constants are lazily constructed, but it's a bit more complicated than that. I'd suggest combining the `enum` with the initialization on demand holder idiom linked by aioobe. Having said that, Bloch argues that lazy initialization isn't a good optimization. It adds unnecessary complexity, is error prone, and rarely improves performance. _Effective Java 2nd Edition, Item 71: Use lazy initialization judiciously_. – polygenelubricants May 26 '10 at 16:57
  • @polygenelubricants What do you mean by "it's a bit more complicated than that"? The Elvis() constructor isn't run until Elvis.THE_ONE is called. Isn't that lazy initialization? – Michael May 26 '10 at 17:50
  • @mangst: the constructor is run when `Elvis` has a `static` initializer block. Or if it has a `static` method, and you call that, even though it has nothing to do with the constants. These are just preliminary results from my own unstructured experimentation. – polygenelubricants May 26 '10 at 17:54
8

I see no problem with your implementation (other than the fact that the lock for the singleton-monitor may be used by other methods, for other reasons, and thus, unnecessarily, prevent some other thread from getting the instance). This could be avoided by introducing an extra Object lock to lock on.

This Wikipedia article suggests another method:

public class Something {
    private Something() {
    }

    private static class LazyHolder {
        private static final Something INSTANCE = new Something();
    }

    public static Something getInstance() {
        return LazyHolder.INSTANCE;
    }
}

From the article:

This implementation is a well-performing and concurrent implementation valid in all versions of Java.
...
The implementation relies on the well-specified initialization phase of execution within the Java Virtual Machine (JVM); see section 12.4 of Java Language Specification (JLS) for details.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • yep, this one is better. Because until you access the static inner class' variable `INSTANCE`, it will not be initialized (lazy). And that initialization is only once. thanks. – Parth May 26 '10 at 11:25
5

My preference is to just do:

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

    private Singleton(){}

    public Singleton instance(){
        return INSTANCE;
    }
 }

It is rare that you need lazy initialization. You should always start with eager initialization and only change to lazy initialization if you see problems. Unless you have measured and pinpointed Singleton instantiation as the culprit of performance problem, just use eager initialization. It's simpler and more performant.

You could use enum for sure, but personally I don't bother because the benefit over normal eager instantiation is security (against reflection attack), and most of the time my code is vulnerable to such attacks anyways :p

Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
2

Josh Bloch recommends 2 solutions:

1) worser:

class Singleton {

   public static Singleton instance = new Singleton();

   ...
}

2) better:

public enum Singleton {

   INSTANCE;

   ...
}
Roman
  • 64,384
  • 92
  • 238
  • 332
1

You can use this snippet of code from wiki

public class Singleton {
   // Private constructor prevents instantiation from other classes
   private Singleton() {}

   /**
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before.
    */
   private static class SingletonHolder { 
     private static final Singleton INSTANCE = new Singleton();
   }

   public static Singleton getInstance() {
     return SingletonHolder.INSTANCE;
   }
 }
Vinay Lodha
  • 2,185
  • 20
  • 29