You don't need double locking. AT ALL.
The idea is generally 'hey, it is a waste of time to create that singleton unless code actually needs that singleton, so lets make it only the first time somebody needs it'.
A fair consideration, though, of course, in practice, the vast majority of singletons do no relevant initialization process whatsoever (their constructors are empty or trivial). Even if not, java already applies this principle for classes itself. You may think that java, upon starting, loads every class on the classpath first, and only then starts executing your app by invoking your main
method. Not so. Instead, java loads nothing, and starts by executing your main method. As part of doing this, your main class will have to be loaded. And as part of doing that, everything your main class 'touches' is soft-loaded.
Touched by your main class means e.g. one of the fields in your main class has String
as a type, or of course String
which shows up in the signature of the main method - that causes the java classloader system to pause its attempting to actually execute your main
method and go load String
instead.
The process ends there though - in basis just because you mention a type someplace in Main
does not mean java will then fully load that type (i.e. load everything that touches, like tracing a path across a spiderweb that soon colours in the entire web). Instead those types are only 'fully loaded' once you execute code that actually uses that type.
And, of course, once some type has been loaded, java ensures it is never loaded a second time, and, java ensures any given class is never initialized twice, even if 2 threads try to use a class for the first time simultaneously. e.g. if you do:
class Test {
private static final String foo = hello();
private static String hello() {
System.out.println("Hello!");
return "";
}
}
Any execution of any java program with the above code in it has only three options:
Hello!
is never printed - if this class is never 'needed' to be loaded.
It is printed exactly once, ever, for the lifetime of that JVM.
More than once, but only if you add more classloaders which effectively means clones of this class end up being loaded which is an academic corner case that doesn't count (had you used double locking it would also initialize more than once in this case).
This is simpler and faster than anything you could possibly do here.
Hence, do not lazy load singletons. Yes, a billion tutorials mention it. They're all wrong. It happens. There are entire wikipedia articles about commonly believed falsehoods. Objective proof (such as the above) showing a belief is false should be heeded even if the belief is widespread.
Thus, we get to the right answer for 99.5% of all singletons:
class MySingleton {
private static final MySingleton INSTANCE = new MySingleton();
public static MySingleton of() {
return INSTANCE;
}
}
Simple. Effective. and already lazy-loading because java's class loader system itself is lazy loading.
The one exception to this rule, which should come up almost never, is if it is reasonable to expect that code will 'touch' a class (mention the class someplace, e.g. use ThatSingleton.class
as an expression or have a method that has a parameter of type ThatSingleton
which nobody is likely to ever call), but never actually want an instance of the singleton. That is an extremely weird situation to be in - normally if anybody so much as mentions the singleton type, that code will immediately invoke the 'get me that singleton' method. After all, the primary reason to mention a type but not call the 'get me the singleton' method is if you want to invoke static methods on it. Who makes singletons with static methods? That's... silly.
The exception applies to me!
I doubt it.
But if it does, we can still rely on the best, safest, fastest 'init only once' mechanism java offers, which is the classloader:
public class MySingleton {
public static MySingleton of() {
class MySingletonHolder {
static final MySingleton INSTANCE = new MySingleton();
}
return MySingletonHolder.INSTANCE;
}
}
EDIT: The above snippet is a nice suggestion by /u/Holger, but it requires a relatively new java version as sticking static
things in inner classes used to be invalid java code. If compiling the above code tells you that 'you cannot put static elements in a non-static class' or similar, simply move the Holder
class outside the method and mark it private static final
.
This is objectively and in an absolute sense (As in, no exceptions, period) the best option - even in that exceedingly exotic case as described before. new MySingleton()
will never be executed unless somebody invokes of()
, in which case it will be executed precisely once. No matter how many threads are doing it simultaneously.
Explanatory: What's wrong with your snippets
Your question inherently implies that you think synchronized
is either simpler than volatile
, faster than volatile
, or both. This simply is not true: volatile
is usually faster, which is why the volatile
example shows up more often as 'the best way to do it' (it is not - using the classloader is better, see above).
Explanatory: What is the hubbub about?
The general problem with your synchronized
example is that any call to of()
will have to acquire a lock and then release it immediately after checking that, indeed, INSTANCE
is already set. Just the synchronized
part (the acquiring of the lock) is, itself, quite slow (thousands, nay, millions of times slower than new MySingleton()
unless your singleton constructor does something very very serious, such as parse through a file). You pay this cost even days after your app has started - after all, every call to of()
, even the millionth, still has to go through synchronized
.
The various tricks such as double-locking etc try to mitigate that cost - to stop paying it once we've gotten well past initializing things. The simple double-locking doesn't actually 'work' (is not guaranteed to only ever make 1 instance), with volatile
it does and now you're paying the lesser, but still significant cost of reading a volatile field every time anybody calls the 'get me the singleton instance' method. This also is potentially quite slow.
All java code has to go through the initialisation gate anytime it touches any class. Which is why the classloader system has very efficient processes for this. Given that you already have to pass that gate, might as well piggyback your lazy initialization needs off of it - which gets us back to: Use my first snippet. Unless you have written something completely ridiculous such as a singleton that also has static methods, in which case, use my second snippet. And know that all blogs, tutorials, examples, etc that show any sort of double locking anything are all far worse.