Depending on the usage, there are several "correct" answers.
Since java5 the best way to do it is to use an enum:
public enumFoo {
INSTANCE;
}
The Right Way to Implement a Serializable Singletonpublic enumElvis {
INSTANCE;private final String[] favoriteSongs ={"Hound Dog", "Heartbreak Hotel"};public voidprintFavorites() {
System.out.println(Arrays.toString(favoriteSongs));
}
}
理解:JDK5之后,建议用用枚举类的方式实现单例的方式。
Pre java5, the most simple case is:
public final classFoo {private static final Foo INSTANCE = new Foo(); //加载Foo的时候对INSTANCE进行了实例化
privateFoo() {if (INSTANCE != null) {throw new IllegalStateException("Already instantiated");
}
}public staticFoo getInstance() {returnINSTANCE;
}
}
Let's go over the code. First, you want the class to be final. In this case, I've used thefinalkeyword to let the users know it is final. Then you need to make the constructor private to prevent users to create their own Foo. Throwing an exception from the constructor prevents users to use reflection to create a second Foo. Then you create aprivate static final Foofield to hold the only instance, and apublic static Foo getInstance()method to return it. The Java specification makes sure that the constructor is only called when the class is first used.
When you have a very large object or heavy construction code AND also have other accessible static methods or fields that might be used before an instance is needed, then and only then you need to use lazy initialization.
You can use aprivate static classto load the instance. The code would then look like:
public final classFoo {private static classFooLoader {private static final Foo INSTANCE = newFoo();
}privateFoo() {if (FooLoader.INSTANCE != null) {throw new IllegalStateException("Already instantiated");
}
}public staticFoo getInstance() {return FooLoader.INSTANCE; //调用getInstance()方法时对FooLoader类进行了加载并实例化了INSTANCE
}
}
Since the lineprivate static final Foo INSTANCE = new Foo();is only executed when the class FooLoader is actually used, this takes care of the lazy instantiation, and is it guaranteed to be thread safe.
When you also want to be able to serialize your object you need to make sure that deserialization won't create a copy.
public final class Foo implementsSerializable {private static final long serialVersionUID = 1L;private static classFooLoader {private static final Foo INSTANCE = newFoo();
}privateFoo() {if (FooLoader.INSTANCE != null) {throw new IllegalStateException("Already instantiated");
}
}public staticFoo getInstance() {returnFooLoader.INSTANCE;
}
@SuppressWarnings("unused")privateFoo readResolve() {returnFooLoader.INSTANCE;
}
}
The methodreadResolve()will make sure the only instance will be returned, even when the object was serialized in a previous run of your program.
While implementing Singleton we have 2 options
1. Lazy loading
2. Early loading
Lazy loading adds bit overhead(lots of to be honest) so use it only when you have a very large object or heavy construction code AND also have other accessible static methods or fields that might be used before an instance is needed, then and only then you need to use lazy initialization.Otherwise choosing early loading is a good choice.
Most simple way of implementing Singleton is
public classFoo {//It will be our sole hero
private static final Foo INSTANCE = newFoo();privateFoo() {if (INSTANCE != null) {//SHOUT
throw new IllegalStateException("Already instantiated");
}
}public staticFoo getInstance() {returnINSTANCE;
}
}
Everything is good except its early loaded singleton. Lets trylazy loaded singleton
classFoo {//Our now_null_but_going_to_be sole hero
private static Foo INSTANCE = null;privateFoo() {if (INSTANCE != null) {//SHOUT
throw new IllegalStateException("Already instantiated");
}
}public staticFoo getInstance() {//Creating only when required.
if (INSTANCE == null) {
INSTANCE= newFoo();
}returnINSTANCE;
}
}
So far so good but our hero will not survive while fighting alone with multiple evil threads who want many many instance of our hero. So lets protect it from evil multi threading
classFoo {private static Foo INSTANCE = null;//TODO Add private shouting constructor
public staticFoo getInstance() {//No more tension of threads
synchronized (Foo.class) {if (INSTANCE == null) {
INSTANCE= newFoo();
}
}returnINSTANCE;
}
}
but it is not enough to protect out hero, Really!!! This is the best we can/should do to help our hero
classFoo {//Pay attention to volatile
private static volatile Foo INSTANCE = null;//TODO Add private shouting constructor
public staticFoo getInstance() {if (INSTANCE == null) { //Check 1
synchronized (Foo.class) {if (INSTANCE == null) { //Check 2
INSTANCE = newFoo();
}
}
}returnINSTANCE;
}
}
This is called "Double-Checked Locking idiom". It's easy to forget the volatile statement and difficult to understand why it is necessary.
Now we are sure about evil thread but what about the cruel serialization? We have to make sure even while de-serialiaztion no new object is created
class Foo implementsSerializable {private static final long serialVersionUID = 1L;private static volatile Foo INSTANCE = null;//Rest of the things are same as above//No more fear of serialization
@SuppressWarnings("unused")privateFoo readResolve() {returnINSTANCE;
}
}
The method readResolve() will make sure the only instance will be returned, even when the object was serialized in a previous run of our program.
Finally we have added enough protection against threads and serialization but our code is looking bulky and ugly. Lets give our hero a make over
public final class Foo implementsSerializable {private static final long serialVersionUID = 1L;//Wrapped in a inner static class so that loaded only when required
private static classFooLoader {//And no more fear of threads
private static final Foo INSTANCE = newFoo();
}//TODO add private shouting construcor
public staticFoo getInstance() {returnFooLoader.INSTANCE;
}//Damn you serialization
@SuppressWarnings("unused")privateFoo readResolve() {returnFooLoader.INSTANCE;
}
}
Yes this is our very same hero :)
Since the line private static final Foo INSTANCE = new Foo(); is only executed when the class FooLoader is actually used, this takes care of the lazy instantiation,
and is it guaranteed to be thread safe.
And we have came so far, here is the best way to achieve everything we did is best possible way
public enumFoo {
INSTANCE;
}
Which internally will be treated like
public classFoo {//It will be our sole hero
private static final Foo INSTANCE = newFoo();
}