|
The Java Specialists' Newsletter
Issue 061 2002-12-07
Category:
Performance
Java version: Double-checked lockingby Dr. Heinz M. Kabutz
Welcome to the 61st edition of The Java(tm) Specialists' Newsletter sent to 5261 Java
Specialists in 91
countries. Since my last newsletter I had the fortune of
celebrating yet another birthday - try guess how old I am ;-)
Has your application ever caused an OutOfMemoryError?
Would you like to know how you can receive a warning
before that actually happens? Have a look at Issue
092.
Double-checked Locking *yawn*
No newsletter writer can claim that he is successful if he has
not at least once written about double-checked locking and how
it is theoretically broken. It is the ideal topic to write about.
When you read my theoretical proofs, you will think I am very
clever, thus enabling me to raise my rates next time you ask
for help. At the same time, the problems described only happen
on a fast multi-processor machine, and it is unlikely that you have one
of those standing at home, so you cannot even contradict
me.
Let's take the Singleton pattern, described in the my Design Patterns Course
. If a Singleton does
not need to be extendible, I write it like this:
public class Singleton {
private final static Singleton instance = new Singleton();
public static Singleton getInstance() { return instance; }
private Singleton() {}
// other methods that you would need to do the actual work
}
The class will be loaded when it is needed at which point the
instance field is created.
Another way of writing the Singleton is:
public class Singleton {
private static Singleton instance;
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
private Singleton() {}
// other methods that you would need to do the actual work
}
The advantage of that approach is that the Singleton instance is only
created when you first use it. However, the class loader would
usually take care of that aspect anyway, so we do not really win
anything by complicating our lives like this. It does not win us
anything, but at least it works.
The problem with the new Singleton is that every time you call
getInstance(), you will have to synchronize, even though you only
really should need to the first time. Clever people have thus
come up with this pattern:
public class Singleton {
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
private Singleton() {}
// other methods that you would need to do the actual work
}
That mechanism is commonly called "Double-Checked Locking"
or DCL for short. It is broken, at least in theory.
In theory what may happen is that due to byte reordering,
before the first thread has finished setting up the Singleton,
i.e. has finished calling the constructor of the Singleton,
the second thread already has a handle to it. In theory,
therefore, it is possible that a thread can get a handle to
a half-baked object using this mechanism.
I have tried to gather some evidence that with the current
JVM implementations the problem can occur. I have written test
code and executed it on a friend's multi-processor. I was not
successful in proving my assertions. I have spoken to a number of authors who have
written about this problem, and they also do not have firm
evidence that this occurs in the real world. I therefore
offer no proof or even claim that what I wrote about in
this newsletter is true.
That is really all I have to say about the matter. Avoid
the double-checked locking to avoid synchronization. In JDK 1.5
they are tidying up the memory model thus showing more clearly
that DCL is broken. In the meantime, try not to be too clever ;-)
Here is a challenge: I have not found a Singleton that is extendable
in such a way that at compile time it is checked that there is only ever one
instance. During my Design
Patterns Course, I usually spend quite
a bit of time on the Singleton, discussing things like why it is a
pattern to avoid, what the differences between a Singleton and class methods are, etc.
One of the issues we spend some time thinking about is the whole
issue of making the Singleton extendable - I call it a polymorphic
Singleton.
That's it for this week.
Heinz
Performance Articles
Related Java Course
|