Double-Checked Locking in Synchronized Java Code
I learned a fun bit of java trivia the other day, that I thought I'd share. Let's say you have a lazy-loaded singleton design including the following code:
...
public static MySingletonClass getInstance() {
if (instance == null) {
instance = new MySingletonClass();
}
return instance;
}
...Of course, in a threaded application, you'll want to make the setting synchronized, so you can be sure that two threads calling getInstance() simultaneously for the first time don't create it twice. So all you need to do is synchronize it, right?
...
public static MySingletonClass getInstance() {
if (instance == null) {
synchronized(MySingletonClass.class) {
instance = new MySingletonClass();
}
}
return instance;
}
...Wrong, you actually need to check it again, inside the method, because it may have changed while the thread was waiting around in the synchronized state, but after the initial null comparison. This is called Double-Checked Locking.
...
public static MySingletonClass getInstance() {
if (instance == null) {
synchronized(MySingletonClass.class) {
if (instance == null) {
instance = new MySingletonClass();
}
}
}
return instance;
}
...Sadly, this may not work either, because of some subtleties in the java memory model that I won't get into here. Unfortunately, there's also no good solution to the problem. You ultimately need to weigh the risk vs. benefits of lazy-loading, as ultimately you'll need to accept the possibility of the class being loaded twice. If it's a simple performance consideration, it may be acceptable, but if your class constructor has any critical side effects (like locking a database connection, or opening a socket), you may have to forgo lazy loading and just use a static instance.
- bsarsgard's blog
- Login or register to post comments
- Printer friendly version


