天天看點

Android--單例模式

版權聲明:本文為部落客原創文章,轉載請标明出處。 https://blog.csdn.net/chaoyu168/article/details/78897883

###定義

保證一個類僅有一個執行個體,并提供一個通路它的全局通路點。
Singleton:負責建立Singleton類自己的唯一執行個體,并提供一個getInstance的方法,讓外部來通路這個類的唯一執行個體。
  • 餓漢式:
    private static Singleton uniqueInstance = new Singleton();
               
  • 懶漢式
    private static Singleton uniqueInstance = null;
               

###功能 單例模式是用來保證這個類在運作期間隻會被建立一個類執行個體,另外,單例模式還提供了一個全局唯一通路這個類執行個體的通路點,就是getInstance方法。

###範圍 Java裡面實作的單例是一個虛拟機的範圍。因為裝載類的功能是虛拟機的,是以一個虛拟機在通過自己的ClassLoader裝載餓漢式實作單例類的時候就會建立一個類的執行個體。

懶漢式單例有延遲加載和緩存的思想

###優缺點

  • 懶漢式是典型的時間換空間
  • 餓漢式是典型的空間換時間
  • 不加同步的懶漢式是線程不安全的。比如,有兩個線程,一個是線程A,一個是線程B,它們同時調用getInstance方法,就可能導緻并發問題。
  • 餓漢式是線程安全的,因為虛拟機保證隻會裝載一次,在裝載類的時候是不會發生并發的。

如何實作懶漢式的線程安全?

加上synchronized即可

public static synchronized Singleton getInstance(){}
           

但這樣會降低整個通路的速度,而且每次都要判斷。可以用雙重檢查加鎖。

雙重加鎖機制,指的是:并不是每次進入getInstance方法都需要同步,而是先不同步,進入方法過後,先檢查執行個體是否存在,如果不存在才進入下面的同步塊,這是第一重檢查。進入同步塊後,再次檢查執行個體是否存在,如果不存在,就在同步的情況下建立一個執行個體。這是第二重檢查。

雙重加鎖機制的實作會使用一個關鍵字volatile,它的意思是:被volatile修飾的變量的值,将不會被本地線程緩存,所有對該變量的讀寫都是直接操作共享記憶體,進而確定多個線程能正确的處理該變量。

/**
 * 雙重檢查加鎖的單例模式
 * @author dream
 *
 */
public class Singleton {

	/**
	 * 對儲存執行個體的變量添加volitile的修飾
	 */
	private volatile static Singleton instance = null;
	private Singleton(){
		
	}
	
	public static Singleton getInstance(){
		//先檢查執行個體是否存在,如果不存在才進入下面的同步塊
		if(instance == null){
			//同步塊,線程安全的建立執行個體
			synchronized (Singleton.class) {
				//再次檢查執行個體是否存在,如果不存在才真正的建立執行個體
				instance = new Singleton();
			}
		}
		return instance;
	}
	
}

           

###一種更好的單例實作方式

public class Singleton {

	/**
	 * 類級的内部類,也就是靜态類的成員式内部類,該内部類的執行個體與外部類的執行個體
	 * 沒有綁定關系,而且隻有被調用時才會裝載,進而實作了延遲加載
	 * @author dream
	 *
	 */
	private static class SingletonHolder{
		/**
		 * 靜态初始化器,由JVM來保證線程安全
		 */
		private static final Singleton instance = new Singleton();
	}
	
	/**
	 * 私有化構造方法
	 */
	private Singleton(){
		
	}
	
	public static Singleton getInstance(){
		return SingletonHolder.instance;
	}
}

           

根據《高效Java第二版》中的說法,單元素的枚舉類型已經成為實作Singleton的最佳方法。

package example6;

/**
 * 使用枚舉來實作單例模式的示例
 * @author dream
 *
 */
public class Singleton {

	/**
	 * 定義一個枚舉的元素,它就代表了Singleton的一個執行個體
	 */
	uniqueInstance;
	
	/**
	 * 示意方法,單例可以有自己的操作
	 */
	public void singletonOperation(){
		//功能樹立
	}
}

           

###本質 控制執行個體數量

###何時選用單例模式 當需要控制一個類的執行個體隻能有一個,而且客戶隻能從一個全局通路點通路它時,可以選用單例模式,這些功能恰好是單例模式要解決的問題。