No, It won't create multiple copies of 'Single'. ( Classloader issue will be visited later )
The implementation you outlined is described as 'Eager Initialization' by in Briant Goetz's book - 'Java Concurrency in Practice'.
public class Single
{
private static Single theInstance = new Single();
private Single()
{
// load properties
}
public static Single getInstance()
{
return theInstance;
}
}
However, the code is not you wanted. Your code is trying to perform lazy-initialization after the instance is created. This requires all the client library to perform 'firstTime()/doPreparation()' before using it. You are going to rely on the client to do right thing which make the code very fragile.
You can modify the code as the following so there won't be any duplicate code.
public class Single
{
private static Single theInstance = new Single();
private Single()
{
// load properties
}
public static Single getInstance()
{
// check for initialization of theInstance
if ( theInstance.firstTime() )
theInstance.doPreparation();
return theInstance;
}
}
Unfortunately, this is a poor implementation of lazy initialization and this will not work in concurrent environment ( like J2EE container ).
There are many articles written about Singleton initialization, specifically on memory model. JSR 133 addressed many weakness in Java memory model in Java 1.5 and 1.6.
With Java 1.5 & 1.6, you have several choices and they are mentioned in the book 'Effective Java' by Joshua Bloch.
- Eager Initialziation, like the above [EJ Item 3]
- Lazy Initalization Holder Class Idiom [EJ Item 71]
- Enum Type [EJ Item 3]
- Double Checked Locking with 'volatile' static field [EJ Item 71]
Solution 3 and 4 will only work in Java 1.5 and above. So the best solution would be #2.
Here is the psuedo-implementation.
public class Single
{
private static class SingleHolder
{
public static Single theInstance = new Single();
}
private Single()
{
// load properties
doPreparation();
}
public static Single getInstance()
{
return SingleHolder.theInstance;
}
}
Notice that 'doPreparation()' is inside of the constructor so you are guarantee to get the properly initialized instance. Also, you are piggying back on JVM's lazy class loading and do not need any synchronization 'getInstance()'.
One thing you noticed that static field theInstance is not 'final'. The example on Java Concurrency does not have 'final' but EJ does. Maybe James's can add more color to his answer on 'classloader' and requirement of 'final' to guarantee correctness,
Having said that, there are a side-effect that with using 'static final'. Java compiler is very aggressive when it sees 'static final' and tries to inline it as much as possible. This is mentioned on a blog posting by Jeremy Manson.
Here is a simple example.
file: A.java
public class A
{
final static String word = "Hello World";
}
file: B.java
public class B
{
public static void main(String[] args) {
System.out.println(A.word);
}
}
After you compile both A.java and B.java, you change A.java to following.
file: A.java
public class A
{
final static String word = "Goodbye World";
}
You recompile 'A.java' and rerun B.class. The output you would get is
Hello World
As for the classloader issue, the answer is yes, you can have more than one instance of Singleton in multiple classloaders. You can find more information on wikipedia. There is also a specific article on Websphere.