設計模式是開發中很重要的一種思想,今天記錄一下單例模式,備忘,哈哈。
first 懶漢式 + 雙重校驗鎖 + 禁止指令重排序優化
public class SingletonOne {
// volatile 禁止指令重排序優化
private static volatile SingletonOne instance = null;
private SingletonOne() {
}
// synchronized 修飾的同步方法比一般的方法要慢很多。所以此處使用雙重校驗鎖。
public static SingletonOne getInstance() {
if (null == instance) {
synchronized(SingletonOne.class) {
if (null == instance) {
instance = new SingletonOne();
}
}
}
return instance;
}}
second 餓漢式 不推薦
public class SingletonTwo {
private static SingletonTwo instance = new SingletonTwo();
private SingletonTwo() {
}
public static SingletonTwo getInstance() {
return instance;
}}
third 靜態內部類加載
public class SingletonThree {
private SingletonThree() {
}
private static class SingletonHolder {
public static SingletonThree instance = new SingletonThree();
}
public static SingletonThree getInstance() {
return SingletonHolder.instance;
}}
fourth 枚舉 目前最爲安全的實現單例的方法是通過內部靜態enum的方法來實現,因爲JVM會保證enum不能被反射並且構造器方法只執行一次。
public class SingletonFour {
private SingletonFour() {
}
private static enum Singleton{
INSTANCE;
private SingletonFour instance;
private Singleton() {
instance = new SingletonFour();
}
public SingletonFour getInstance() {
return instance;
}
}
public static SingletonFour getInstance() {
return Singleton.INSTANCE.instance;
}}
上面提到的三種實現單例的方式都有共同的缺點:
1.需要額外的工作來實現序列化,否則每次反序列化一個序列化的對象時都會創建一個新的實例。
2.可以使用反射強行調用私有構造器(如果要避免這種情況,可以修改構造器,讓它在創建第二個實例的時候拋異常)。
而枚舉類很好的解決了這兩個問題,使用枚舉除了線程安全和防止反射調用構造器之外,還提供了自動序列化機制,
防止反序列化的時候創建新的對象。因此,《Effective Java》作者推薦使用的方法。不過,在實際工作中,很少看見有人這麼寫。