實現Singleton 模式—六種實現方式

1. 餓漢式(線程安全)

public static class Singleton{
	private final static Singleton INSTANCE = new Singleton();
	private Singleton{
	
	}
	public static Singleton getInstance(){
		return INSTANCE;
	}		
}

餓漢模式在類被初始化時就已經在內存中創建了對象,以空間換時間,故不存在線程安全問題。

2. 懶漢式(線程不安全)

public static class Singleton{
	private static Singleton INSTANCE = null;
	private Singleton{

	}
	public static Singleton getInstance(){
		if(INSTANCE == null){
			INSTANCE = new Singleton();
		}
		return INSTANCE;
	}
}

懶漢模式在方法被調用後才創建對象,以時間換空間,在多線程環境下存在風險。

3. 懶漢式(線程安全,多線程下效率不高)

public static class Singleton{
	private static Singleton INSTANCE = null;
	private Singleton{

	}
	public static synchronized Singleton getInstance(){
		if(INSTANCE == null){
			INSTANCE = new Singleton();
		}
		return INSTANCE;
	}
}

4. 懶漢式(線程安全)

public static class Singleton{
	private static Singleton INSTANCE = null;
	static{
		INSTANCE = new Singleton();
	}
	private Singleton{
	
	}
	public static Singleton getInstance(){
		return INSTANCE;
	}
}

5. 雙重鎖懶漢式(線程安全)

public static class Singleton{
	private volatile static Singleton INSTANCE = null;
	private Singleton{
	
	}
	public static Singleton getInstance(){
		if(INSTANCE == null){
			synchnronized(Singleton.class){
				if(INSTANCE == null){
					INSTANCE = new Singleton();
				}
			}
		}
		return INSTANCE;
	}
}

DCL模式的優點就是,只有在對象需要被使用時才創建,第一次判斷 INSTANCE == null爲了避免非必要加鎖,當第一次加載時纔對實例進行加鎖再實例化。這樣既可以節約內存空間,又可以保證線程安全。但是,由於jvm存在亂序執行功能,DCL也會出現線程不安全的情況。具體分析如下:
INSTANCE = new SingleTon();
這個步驟,其實在jvm裏面的執行分爲三步:

1.在堆內存開闢內存空間。
2.在堆內存中實例化SingleTon裏面的各個參數。
3.把對象指向堆內存空間。

由於jvm存在亂序執行功能,所以可能在2還沒執行時就先執行了3,如果此時再被切換到該線程上,由於執行了3,INSTANCE 已經非空了,會被直接拿出來用,這樣的話,就會出現異常。這個就是著名的DCL失效問題

不過在JDK1.5之後,官方也發現了這個問題,故而具體化了volatile,即在JDK1.6及以後,只要定義爲private volatile static SingleTon INSTANCE = null;就可解決DCL失效問題。volatile確保INSTANCE每次均在主內存中讀取,這樣雖然會犧牲一點效率,但也無傷大雅。

6. 靜態內部類(線程安全,推薦)

public static class Singleton{
    private final static class SingletonHolder{
        private final static Singleton INSTANCE = new Singleton();
    }
    private Singleton{

    }
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章