標籤:
單利模式:確保一個類最多隻有一個執行個體,並提供一個全域訪問點。
經典單利模式建立對象代碼
public class Singleton { private static Singleton uniqueInstance = null; private Singleton(){ } public static Singleton getInstance(){ if (uniqueInstance==null) { uniqueInstance=new Singleton(); } return uniqueInstance; }}
問題:多線程
public class Q { //多線程 private static Q uniqueInstance = null; private Q(){ } public static Q getInstance(){ if (uniqueInstance==null) {//當線程1執行此語句後,判斷通過, /*正準備執行uniqueInstance=new Q()時,線程2搶佔到了cpu資源, *切換到線程2開始執行,線程2會發現uniqueInstance還是null,所以會建立對象,建立完後, *而當切換到線程1時,發現線程1已經進入if判斷,所以也會建立一個新uniqueInstance, *此時線程1建立的uniqueInstance和線程2建立的uniqueInstanc是不一樣的 **/ uniqueInstance=new Q(); } return uniqueInstance; }}
解決辦法
1、建立對象的方法加同步鎖
/** * 最佳化方式1 * 方法添加同步鎖 * 優點:使用方便 * 缺點:當線程很多的情況下,非常耗費資源 * @author yxm * */public class Optimization_Singleton_1 { private static Optimization_Singleton_1 uniqueInstance = null; private Optimization_Singleton_1(){ } public synchronized static Optimization_Singleton_1 getInstance(){ if (uniqueInstance==null) { uniqueInstance=new Optimization_Singleton_1(); } return uniqueInstance; }}
2、餓漢式建立對象
/** * 最佳化方式2 * 急切建立對象 * 優點:不會因為加鎖而耗費資源 * 缺點:當不使用此類時,照樣會耗費記憶體 * @author yxm * */public class Optimization_Singleton_2 { private static Optimization_Singleton_2 uniqueInstance = new Optimization_Singleton_2(); private Optimization_Singleton_2(){ } public static Optimization_Singleton_2 getInstance(){ if (uniqueInstance==null) { uniqueInstance=new Optimization_Singleton_2(); } return uniqueInstance; }}
3、雙重檢查加鎖 (較完美)
/** * 最佳化方式3 * 雙重檢查加鎖 * 較完美 * @author yxm * */public class Optimization_Singleton_3 { private volatile static Optimization_Singleton_3 uniqueInstance = null;//volatile給編譯器使用,保證安全執行緒 private Optimization_Singleton_3(){ } public synchronized static Optimization_Singleton_3 getInstance(){ if (uniqueInstance==null) {
//只有等線程1把對象建立好了,其他線程才會進入以下代碼塊 synchronized(Optimization_Singleton_3.class){ if (uniqueInstance==null) { uniqueInstance=new Optimization_Singleton_3(); } } } return uniqueInstance; }}
案例:一個巧克力工廠,生產各式各樣的巧克力,生產過程有(準備原料、填充、加熱、排出)四道工序,但是現在工廠裡只有一條生產線,意味著一次只能生產一種巧克力,請問如何把控?
分析:轉換為電腦思維,此情境是典型的一個類只能有一個對象,符合單利模式特徵
普通巧克力工廠
public class ChocolateFactory { private boolean empty; private boolean boiled; public ChocolateFactory(){ empty=true; boiled=false; } //填充 public void fill(){ if (empty) { empty=false; boiled=false; } } //加熱 public void boil(){ if (!boiled) { boiled=true; } } //排出 public void drain(){ if (!empty&&boiled) { empty=true; } }}
使用單利模式後的巧克力工廠
public class ChocolateFactoryInSingleton { private boolean empty; private boolean boiled; public static ChocolateFactoryInSingleton uniqueInstance=null; private ChocolateFactoryInSingleton(){ empty=true; boiled=false; } public static ChocolateFactoryInSingleton getInstance(){
//此處確保不同的巧克力不會進入同一條生產線 if (uniqueInstance==null) { uniqueInstance=new ChocolateFactoryInSingleton(); } return uniqueInstance; } //填充 public void fill(){ if (empty) { empty=false; boiled=false; } } //加熱 public void boil(){ if (!boiled) { boiled=true; } } //排出 public void drain(){ if (!empty&&boiled) { empty=true; } }}
Java設計模式の單利模式