單例的五種寫法

懶漢式(線程不安全)

  • 這段代碼比較簡單,使用了懶加載模式,但卻存在致命的問題。當有多個線程並行調用 getInstance() 的時候,就會創建多個實例。也就是說在多線程下不能正常工作。
    package singleton;
/**
 * 懶漢式
 * @author 落幕
 *
 */
public class LazySingleTon {
	
	private LazySingleTon() {
		
	}
	
	private static LazySingleTon lazy = null;
	
	public static LazySingleTon getInstance(){
		if(lazy == null){
			lazy = new LazySingleTon();
		}
		return lazy;
	}
}
  • 線程安全的懶漢式,但因爲synchronized鎖的是方法,嚴重影響性能。
/**
 * 懶漢式
 * @author 落幕
 *
 */
public class LazySingleTon {
	
	private LazySingleTon() {
		
	}
	
	private static LazySingleTon lazy = null;
	
	public static synchronized LazySingleTon getInstance(){
		if(lazy == null){
			lazy = new LazySingleTon();
		}
		return lazy;
	}
}

餓漢式

  • 這種方法非常簡單,因爲單例的實例被聲明成 static 和 final 變量了,在第一次加載類到內存中時就會初始化,所以創建實例本身是線程安全的。
package singleton;

/**
 * 餓漢式
 * @author 落幕
 *
 */
public class EagerSingleton {
	
	private EagerSingleton() {
		// TODO Auto-generated constructor stub
	}
	
	private static final EagerSingleton eager = new EagerSingleton();
	
	public static EagerSingleton getInstance(){
		return eager;
	}
}

雙重檢測機制(DCL)懶漢式

  • 雙重檢測機制,是一種使用同步塊加鎖的方法。程序員稱其爲雙重檢查鎖,因爲會有兩次檢查 instance == null,一次是在同步塊外,一次是在同步塊內。爲什麼在同步塊內還要再檢驗一次?因爲可能會有多個線程一起進入同步塊外的 if,如果在同步塊內不進行二次檢驗的話就會生成多個實例了。
package singleton;

/**
 * 雙重檢測機制(DCL)懶漢式
 * @author 落幕
 *
 */
public class LockSingleton {
	
	private LockSingleton() {
		// TODO Auto-generated constructor stub
	}
	//volatile有內存屏障的功能,可以防止重排序問題,至於重排序這個問題大家可以上網搜搜相關資料
	private static volatile LockSingleton lock = null;
	
	public static LockSingleton getInstance(){
		if(lock == null){
			synchronized(LockSingleton.class){
				//判斷是否爲null,提高性能
				if(lock == null){
				    //此處非原子性操作,所以需要在lock上加volatile關鍵字
					lock = new LockSingleton();
				}
			}
		}
		return lock;
	}
}

靜態內部類實現單例

  • 推薦使用此方法,這種寫法使用JVM本身機制保證了線程安全問題;初始化靜態數據時,Java提供了的線程安全性保證。除了getInstance() 之外沒有辦法訪問它,因此它是懶漢式的;同時讀取實例的時候不會進行同步,沒有性能缺陷,也不依賴JDK版本。
package singleton;
/**
 * 靜態內部類
 * @author 落幕
 *
 */
public class StaticClass {
	
	private StaticClass() {
		// TODO Auto-generated constructor stub
	}
	
	
	private static class ClassLoaders {
		private static final StaticClass instance = new StaticClass();
	}
	
	public static StaticClass getInstance(){
		return ClassLoaders.instance;
	}
	
}

枚舉實現單例

  • 也較推薦這種寫,簡單明瞭,並且線程安全,而且還能防止反序列化導致重新創建新的對象
package singleton;

/**
 * 枚舉實現單例
 * @author 落幕
 *
 */
public enum EnumSingleton {
	INSTANCE;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章