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