大話設計模式——單例模式(Singleton)

單例模式(Singleton)是java中一個比較常見的設計模式,單例對象主要是爲了保證在一個JVM中,該對象只有一個實例存在。主要優點:java

(1) 減小一些大型對象的開銷,減小內存的佔用面試

(2) 省去了new操做,較少了GC的壓力設計模式

(3) 保證了一些核心類只被建立一次,好比一些核心的調度類,一些主要的操做類只被建立一次。安全

單例模式最多見的兩種實現模式:餓漢式,懶漢式,內部靜態類實現,雙重檢驗鎖模式函數

1.餓漢式:在進行類加載時就建立好 (添加了synchronized保證了線程的安全性)優化

package designPatterns;

public class SingletonHungry {
	
	private static SingletonHungry instance = new SingletonHungry();
	
	//私有構造函數,防止被實例化
	private SingletonHungry(){
		
	}
	
	public static SingletonHungry getInstance(){ 
		return instance;
	}

}   

 

2. 懶漢式:延遲加載,在用到的時候才進行建立spa

package designPatterns;

public class SingletonLazy {
    
    private static SingletonLazy instance = null;
    
    //私有構造函數,防止被實例化
    private SingletonLazy(){
        
    }

    public static SingletonLazy getInstance(){
        if(instance == null){
            instance = new SingletonLazy();
        }
        return instance;
    }
}

固然懶漢模式是線程不安全的,爲了保證線程安全,咱們能夠將函數定義成synchronized的,可是實際上,並非每次都須要同步的,只是在第一次建立對象的時候須要確保同步,所以咱們能夠只同步一個對象。以下線程

package designPatterns;

public class SingletonLazy {
	
	private static SingletonLazy instance = null;
	
	//私有構造函數,防止被實例化
	private SingletonLazy(){
		
	}

	/*
	public static SingletonLazy getInstance(){
		if(instance == null){
			instance = new SingletonLazy();
		}
		return instance;
	}
	*/
	
	public static SingletonLazy getInstance(){
		if(instance == null){
			synchronized(instance){
				if(instance == null){
					instance = new SingletonLazy();
				}
			}
		}
		return instance;
	}
}

  可是,因爲java中建立對象和賦值操做是分開進行的,也就是說instance = new SingletonLazy()這句話是分步執行的。JVM的即時編譯存在指令重派的優化,2,3步的操做是沒法肯定的。設計

       1. 給instance分配內存code

       2. 調用構造函數初始化成員變量

       3. 將instance對象指向分配的內存空間(執行完這句話以後instance纔會變成非null的)

 

兩步執行的,可能先執行分配空間,再初始化,這也可能會致使A,B兩個線程不一樣步,因此還有一種方法是使用內部靜態類來進行實現,內部靜態類在另外一篇博客中有詳細介紹,這裏再也不贅述。

3. 靜態內部類,代碼以下:

package designPatterns;

public class Singleton {
    
    //私有構造方法,防止被實例化
    private Singleton(){
        
    }
    
    //靜態內部類建立實例
    private static class SingletonFactory{
        private static Singleton instance = new Singleton();
    }
    
    //獲取實例
    public static Singleton getInstance(){
        return SingletonFactory.instance;
    }
    
    //若是該對象被用於序列化,能夠保證對象在序列化先後保持一致
    public Object readResolve(){
        return getInstance();
    }

}

使用內部靜態類的方法,只有在外部類被調用時纔會被加載,而後new一個實例,這樣就避免了鎖的應用,通常建議使用這種方法,但仍是須要根據實際須要來進行選擇的。

 

4. 雙重檢驗鎖模式(雖然內部類的方法感受更加好用一些,可是不少面試官想讓你寫的仍是雙檢鎖模式)

public class Singleton {
    private volatile static Singleton instance; //volatile的可見性
    private Singleton() {}
    public static Singleton getSingleton() {
        if(instance == null) {         //Single Check
            synchronized(Singleton.class) {
                if(instance == null) {      //Double Check
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

雙檢鎖模式其實就是爲了保證一個順序。雙檢鎖的出現保證了上述2,3句的執行順序。

相關文章
相關標籤/搜索