On 26/05/2010 1:54 PM, Ryan Rawson wrote:
Thanks for that salient comment. Perhaps someone can give us the right
pattern for no lock Singleton initialization.

There are really only two things which complicate thread-safe singletons:

1) Having a setter, so you can replace the singleton
2) Lazy initialization. The only excuse for this is having a horribly-expensive-to-create singleton, which may not even be used, and you don't under any circumstances wish to create it unless it's needed. This is hard to get right, and 99% of the time you should just instantiate it at class initializion time and forget it.

In this case, 1) applies, but 2) doesn't; luckily 1) is a lot easier to get right than 2).

Simplest 'correct' patterns are:


Basic Singleton (neither #1 nor #2 apply)
-------------------------------------------

public class Thing {
   private static final Thing INSTANCE = new AwesomeThing();

   public Thing get() {
      return INSTANCE;
   }
}

this is easy, simple, performant (no synchronization or locking at all) and 100% thread-safe (as long as INSTANCE is final).



Replacable Singleton (#1 applies)
-------------------------------------------
public class Thing {
private static volatile Thing instance = new AwesomeThing(); // Note: volatile

   public Thing get() {
      return instance;
   }

   public void set(Thing newThing) {
      this.instance = newThing;
   }
}

Nearly as easy, all that's required here is a volatile instance which gives you the correct happens-before relationship.



Lazy-Initialized Singleton (#2 applies)
-------------------------------------------
Avoid if possible, but if not, one of:

Synchronized Getter:
   public synchronized Thing get() {
      if (instance == null) {
          instance = new AwesomeThing();
      }
      return instance;
   }

Double-checked locking (ONLY works in Java 5+)
   public Thing get() {
      if (instance == null) {
          synchronized (ThingHolder.class) {
             if (instance == null) { // Yes, you need this
                 instance = new AwesomeThing();
             }
         }
      }
      return instance;

Use java classloading locking guarantees + holder class (see: Effective Java)
   class ThingHolder {
       private static final Thing INSTANCE = new AwesomeThing();
   }

   class Thing {
       public Thing getThing() {
           return ThingHolder.instance;
       }
   }



Lazy-Initialized Settable Singleton (#1 + #2 apply)
-------------------------------------------
You almost certainly don't need this. You think you do, but you don't. Find a better way. :)


Hope that helps.

Cheers,

Paul

Reply via email to