Reputation: 1357
I was reading an article about Double-checked Locking. The problem discussed is as follows:
public class MyFactory {
private static MyFactory instance;
public static synchronized MyFactory getInstance() {
if (instance == null)
instance = new MyFactory();
return instance;
}
private MyFactory() {}
}
One of the suggested ways how to avoid synchronization on every getInstance()
call is to use the class loader:
public class MyFactory {
private static final MyFactory instance;
static {
try {
instance = new MyFactory();
} catch (IOException e) {
throw new RuntimeException("Darn, an error's occurred!", e);
}
}
public static MyFactory getInstance() {
return instance;
}
private MyFactory() throws IOException {
// read configuration files...
}
}
Author says: "... the JVM ensures that this static initialisation code is called exactly once, when the class is first referred to and loaded." Which I totally agree. But I don't understand the follows: "Using the class loader is generally my preferred way of dealing with lazy static initialisation."
Is the second code snippet a lazy static initialisation?
Upvotes: 1
Views: 788
Reputation: 8587
Not exactly. The initialization happens when MyFactory
class was loaded, not when getInstance()
was called. If you want to initialize the instance when the method was called, you can use a holder class.
public class MyFactory {
private static final class Holder {
private static final MyFactory instance = new MyFactory();
}
public static MyFactory getInstance() {
return Holder.instance;
}
}
Upvotes: 1
Reputation: 1073
Playing with Double-checked locking is like playing with fire. There are many ways one can get it wrong.
The purpose of Double-checked locking idiom is to avoid unnecessary synchronization
. Thus your first code snippet doesn't fit into the category.
Coming to your second code snippet, if the singleton you are creating is static
, then there is a compact solution in which you can define the singleton as a static
field in a separate class and not in the same class.
class MyFactorySingleton {
static MyFactory singleton = new MyFactory();
}
This semantics of Java guarantees that the field will not be initialized until the field is referenced, and that any thread which accesses the field will see all of the writes resulting from initializing that field.
But from JDK5 and later, Java has started supporting volatile
semantics which says that
the value of a variable which is declared
volatile
will never be cached thread-locally. All reads and writes will go straight to "main memory". Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.
So, a some what fool proof design for a Double-checked looking should look like this:
class MyFactory {
private volatile MyFactory instance = null;
public MyFactory getInstance() {
if(instance == null) {
synchronized(MyFactory.class) {
if(instance == null) {
instance = new MyFactory();
}
}
}
return instance;
}
}
Prof. Joshua Bloch and his co-authors explains how Double-checked locking can go wrong in this article. It is worth reading this.
Upvotes: 1
Reputation: 143
It is not lazy. This is lazy (using class loader):
public class Singleton {
public static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
Upvotes: 2