[Stan]: Oh, neat, the holder makes it lazy? Yep. This is guaranteed in
JLS 12.4.1 - the Holder class won't be initialized until just before the first time its static field is used.
[Stan]: If you don't care about that - the only methods you use on Something are the member methods on the Singleton - can we just leave the holder out? Absolutely. A non-lazy singleton is even easier for people to understand, and often laziness is not necessary or even desirable.
[EFH]: No, there's a fairly trivial extension to this: Well, if a runtime exception is thrown by a static initializer, then what happens is the JVM wraps it with an ExceptionInInitializerError. So I'm inclined to just throw that in the first place:
This is getting a bit ugly though, interfering with the initial simplicity of the Holder code.
Also annoying is the fact that if someone does catch this Error, then the
second time someone tries to call getInstance(), it throws a NoClassDefFoundError, which has been known to confuse people. From the JVM's perspective, it knows it already found the one class definition, but it errored when it tried to load that definition. So now it just errors again rather than retrying.
[avihai]: This is a big restriction to dont allow to throw any exception that is not run time exception. Hm, I suppose it depends on where you stand on the use of checked exceptions vs. unchecked exceptions or Errors. Personally I tend to avoid throwing checked exceptions, as I want the code calling getInstance() to be easy to write, and I generally figure that if the singleton instance can't be created, there usually isn't a good way to recover anyway. It's usually some sort of configuration error, and the user needs to fix the configuration and restart the application. So throwing an Error in this case usually suits me just fine. If you think you need a better recovery strategy, then yes, throwing a checked exception may be more appropriate.
[avihai]: I think that if the memory mechanism fixed in 1.5 it will be better to use in the violatile solution. Eh, I'd probably still prefer using simple synchronization:
That way (a) I don't have to worry about what happens if someone runs this on an older JVM, and (b) I don't have to spend time convincing other developers (who have heard that double-checked locking is broken) that it's now OK when using volatile and JDK 5+. Because, again, the supposed "cost" of synchronization is usually really trivial compared to the energy people spend trying to avoid it.