Sounds like we want #1: replaceable singleton. does that sound right?
On Tue, May 25, 2010 at 9:16 PM, Paul Cowan <[email protected]> wrote: > 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 >
