- best practice: Sinigleton w/
enum
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
- pro:
- concise, and thread-safe.
-
enum
is singleton by design. All theenum
values are initialized only once when class loaded. -
enum
支持反序列化機制巾陕,無需實現(xiàn)Serializable
接口和重寫readResolve()
方法怕敬,即可避免反序列化中對單例模式的破壞。 -
enum
can’t be initialized via reflection. 試圖通過反射方式得到單例對象屏歹,會報錯:java.lang.IllegalArgumentException: Cannot reflectively create enum objects
.
- con: none.
- Traditional Methods of Making Singletons:
2.1 : Eagerly Initialized Singleton
public class EagerSingleton {
/** private constructor to prevent others from instantiating this class */
private EagerSingleton() {}
/** Create an instance of the class at the time of class loading */
private static final EagerSingleton instance = new EagerSingleton();
/** Provide a global point of access to the instance */
public static EagerSingleton getInstance() {
return instance;
}
}
- pro: thread-safe.
- con: the instance is created irrespective of whether it is accessed or not. This is fine if the object is simple and does not hold any system resources. But can have performance implications if it allocates a large amount of system resources and remains unused.
2.2 : Eagerly Initialized Static Block Singleton
public class EagerStaticBlockSingleton {
private static final EagerStaticBlockSingleton instance;
/** Don't let anyone else instantiate this class */
private EagerStaticBlockSingleton() {}
/** Create the one-and-only instance in a static block */
static {
instance = new EagerStaticBlockSingleton();
}
/** Provide a public method to get the instance that we created */
public static EagerStaticBlockSingleton getInstance() {
return instance;
}
}
- pro:thread-safe.
- con:the instance is created whether or not it is needed by the application.
2.3 : Lazily Initialized Singleton
public class LazySingleton {
private static LazySingleton instance;
/** Don't let anyone else instantiate this class */
private LazySingleton() {}
/** Lazily create the instance when it is accessed for the first time */
public static synchronized LazySingleton getInstance() {
if(instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
- pro:The
synchronized
keyword ensures thread-safety. - con:The
synchronized
solution is kinda inefficient.
2.4 : Lazily Initialized Double-Checked Locking Singleton
public class LazyDoubleCheckedLockingSingleton {
private static volatile LazyDoubleCheckedLockingSingleton instance;
/** private constructor to prevent others from instantiating this class */
private LazyDoubleCheckedLockingSingleton() {}
/** Lazily initialize the singleton in a synchronized block */
public static LazyDoubleCheckedLockingSingleton getInstance() {
if(instance == null) {
synchronized (LazyDoubleCheckedLockingSingleton.class) {
// double-check
if(instance == null) {
instance = new LazyDoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
- pro:the use of
volatile
keyword is necessary here to prevent compilers from doing their own optimizations (like instruction reordering). and it's thread-safe. - con:not very efficient.
2.5 Lazily Initialized Inner Class Singleton
public class LazyInnerClassSingleton {
/** private constructor to prevent others from instantiating this class */
private LazyInnerClassSingleton() {}
/** This inner class is loaded only after getInstance() is called for the first time. */
private static class SingletonHelper {
private static final LazyInnerClassSingleton INSTANCE = new LazyInnerClassSingleton();
}
public static LazyInnerClassSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
- pro: most efficient due to the reason that the inner class is not loaded until the
getInstance()
method is invoked for the first time. This solution is thread-safe and doesn’t require any other synchronization. - con: none.
Conclusion:
- The examples above are several thread-safe ways of implementing the singleton design pattern. (who would want thread-unsafe solutions?)
- Last but not the least, 簡單描述一下單例模式的應(yīng)用場景:
單例模式能保證在一個JVM中揭北,對象只有一個實例存在。正是由于這個特點吏颖,單例對象通常作為程序中的存放配置信息的載體搔体,因為它能保證其他對象讀到一致的信息。例如在某個服務(wù)器程序中半醉,該服務(wù)器的配置信息可能存放在數(shù)據(jù)庫或文件中疚俱,這些配置數(shù)據(jù)由某個單例對象統(tǒng)一讀取,服務(wù)進(jìn)程中的其他對象如果要獲取這些配置信息缩多,只需訪問該單例對象即可呆奕。這種方式極大地簡化了在復(fù)雜環(huán)境下养晋,尤其是多線程環(huán)境下的配置管理,但是隨著應(yīng)用場景的不同梁钾,也可能帶來一些同步問題绳泉。我們具體問題具體分析吧。
EOF