單例模式

1、定義

確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例

2、使用場景

確保某個類有且只有一個對象的場景,避免產生多個對象消耗過多的資源,或者某種類型的對象只應該有且只有一個。

3、五種常見的單例模式

1)餓漢單例模式(推薦)

package com.baofeng.singleton;

/**
 * 餓漢單例模式
 * 
 * @author sus
 * 
 * 優點:加載類的時候就創建實例,所以線程安全
 * 缺點:不能延遲加載
 * 典型的空間換時間
 *
 */
public class Singleton {
	private static final Singleton singleton = new Singleton();

	// 構造函數私有化
	private Singleton() {

	}
	
	public void doSomething(){
		System.out.println("do something");
	}

	public static Singleton getInstance() {
		return singleton;
	}
	
	//call
	//Singleton.getInstance().doSomething();
}

2)懶漢單例模式

/**
 * 懶漢單例模式
 * 
 * @author sus
 *
 * 優點:延遲加載
 * 缺點:需要加鎖才能實現多線程同步,但是效率會降低
 * 典型的時間換空間
 */
public class Singleton1 {
	private static Singleton1 singleton = null;

	// 構造函數私有化
	private Singleton1() {

	}
	
	public void doSomething(){
		System.out.println("do something");
	}

	public static synchronized Singleton1 getInstance() {
		if(singleton == null){
			singleton = new Singleton1();
		}
		return singleton;
	}
	
	//call
    //Singleton1.getInstance().doSomething();
}

3)雙重檢查鎖定(Doublle Check Lock)單例模式(不太推薦)

/**
 * 雙重檢查鎖定(Doublle Check Lock)單例模式
 * 
 * @author sus
 * 
 * 麻煩,在當前Java內存模型中不一定都管用,(DCL失效問題)某些平臺和編譯器甚至是錯誤的,
 * 因爲singleton = new Singleton2()這種代碼在不同編譯器上的行爲和實現方式不可預知。
 *
 */
public class Singleton2 {
	//JDK是1.5或之後的版本添加volatile關鍵字 
	//雙重加鎖機制的實現會使用一個關鍵字volatile,
	//它的意思是:被volatile修飾的變量的值,將不會被本地線程緩存,
	//所有對該變量的讀寫都是直接操作共享內存,從而確保多個線程能正確的處理該變量。
	private volatile static Singleton2 singleton = null;

	// 構造函數私有化
	private Singleton2() {

	}
	
	public void doSomething(){
		System.out.println("do something");
	}

	public static Singleton2 getInstance() {
		//第一層判空是爲了避免不必要的同步
		if (singleton == null) {
			synchronized (Singleton2.class) {
				//第二層判空是爲了在null的情況下創建實例
				if (singleton == null) {
					singleton = new Singleton2();
				}
			}
		}
		return singleton;
	}
	
	//call
	//Singleton2.getInstance().doSomething();
}

4)靜態內部類單例模式(推薦)

/**
 * 靜態內部類單例模式
 * 
 * @author sushuai
 *
 *延遲加載,減少內存開銷。因爲用到的時候才加載,避免了靜態field
 *在單例類加載時即進入到堆內存的permanent代而永遠得不到回收的缺點(大多數垃圾回收算法是這樣)。
 *
 *類級的內部類,也就是靜態類的成員式內部類,該內部類的實例與外部類的實例
 * 沒有綁定關係,而且只有被調用時纔會裝載,從而實現了延遲加載
 */
public class Singleton3 {

	// 構造函數私有化
	private Singleton3() {

	}

	public static Singleton3 getInstance() {
		return SingletonHolder.singleton;
	}
	
	public void doSomething(){
		System.out.println("do something");
	}

	private static class SingletonHolder {
	/**
         * 靜態初始化器,由JVM來保證線程安全
         */
	  private static final Singleton3 singleton = new Singleton3();
	}
	
	//call
	//Singleton3.getInstance().doSomething();
}


5)包含單個元素的枚舉類型的單例模式(極力推薦)

/**
 * 包含單個元素的枚舉類型的單例模式
 * 
 * @author sus
 * 
 * 很好,不僅能避免多線程同步問題,而且還能防止反序列化重新創建新的對象。
 * 但是失去了類的一些特性,沒有延遲加載,用的人也太少了~~
 */
public enum Singleton4 {

	INSTANCE; //定義一個枚舉的元素,就代表Singleton4的一個實例
	
	public void doSomething(){
		System.out.println("do something");
	}
	
	//call
	//Singleton4.INSTANCE.doSomething();
	//單元素的枚舉類型已經成爲實現Singleton的最佳方法
}
發佈了97 篇原創文章 · 獲贊 87 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章