天天看點

java 設計模式之單例模式(單線程、多線程下)

單例模式分為兩種:餓漢式和懶漢式(飽漢式)。

餓漢式:類加載的時候已經建立好了對象,随使随用。

            建立步驟

         1. 構造方法私有化,從外界不能構造此類的對象

         2. 靜态私有變量 并初始化,類加載的時候已經被初始化

         3. 提供一個靜态的公共的方法供外界通路

懶漢式(飽漢式):什麼時候用,再建立對象.需要注意線程安全問題,有延遲加載的特性。

            建立步驟

        1.構造方法私有化,從外界不能構造此類的對象

        2.靜态私有變量,沒有被顯示初始化,隻是預設的null值

        3.線程安全地獲得靜态私有對象變量的值

開發中常用餓漢式,代碼簡潔,沒有線程安全問題

JDK中的單例模式:Runtime類的源碼如下圖所示

java 設計模式之單例模式(單線程、多線程下)

顯而易見Runtime類是使用了餓漢式的單例模式

餓漢式:适用于單線程、多線程

package siglepattern;
/**
 * 餓漢式 沒有線程安全問題
 * @author feige
 */
public class StudentHungerPattern {
    //構造方法私有化
   private StudentHungerPattern(){   
   }
   //靜态私有變量 并初始化
   private static StudentHungerPattern student=new StudentHungerPattern();
   //靜态的公共的方法供外界通路,來獲得對象
   public static StudentHungerPattern getStudent(){
       return student;
   }
}
           

适用于單線程的懶漢式

package siglepattern;

//單線程下的延遲加載(懶漢式)
public class UnSafeLazyInitialization {
 private static Instance instance=null;
 
 public static Instance getInstance(){
	 if(instance==null){
		 instance=new Instance();
	 }
	 return instance;
 }

//構造方法私有化

private UnSafeLazyInitialization(){}}
           

适用于多線程的懶漢式(效率不高)

package siglepattern;
/**
 * 懶漢式(飽漢式)
 * @author feige
 */
public class StudentFill {
private StudentFill(){}//構造方法私有化,
private static StudentFill student=null;
public synchronized static StudentFill getStuddent(){//注意線程安全
    if(student==null){
        student=new StudentFill();
    }
    return student;
}
}
           

由于對getStudent()方法作了同步處理,synchronized将導緻性能開銷

多線程下懶漢式的同步處理優化---》安全的雙重檢查鎖定

1.volatile(适用于執行個體字段、靜态字段的初始化)

package siglepattern;

public class SafeDoubleChekedLocking {
private volatile static Instance instance=null;

public static Instance getInstance(){
	if(instance==null){
		synchronized(SafeDoubleChekedLocking.class){
			if(instance==null){
				instance=new Instance();
			}
		}
	}
	return instance;
}
private SafeDoubleChekedLocking(){}
}
           

2.基于類初始化(适用于靜态字段的初始化)

package siglepattern;

public class InstanceFactory {
 private static class InstanceHolder{
	 public static Instance instance=new Instance();
 }
 public static Instance getInstance(){
	 return InstanceHolder.instance;
 }
}
           

我們一般使用volatile對執行個體字段進行初始化,靜态字段的初始化用基于類初始化

繼續閱讀