單例模式理解

單例模式在開發過程中

遇到的幾個場景:
       1、網站計數器,一般是採用單例模式實現,否則難以同步。
       2、由於配置文件一般都是共享資源,即web應用的配置對象的讀取,一般採用單例模式來實現。如:spring的配置文件的讀取等
       3、多線程的線程池的設計一般也是採用單例模式,這是由於線程池要方便對池中的線程進行控制。
       4、數據庫連接池的設計也是採用單例模式的。數據庫連接其實也是一種數據連接的共享資源,在jdbc連接中如果在做頻繁操作的時候,不停的打開或者關閉會效能損耗,因此用單例模式來維護就大大降低了這種效能損耗。

       其實,通過介紹單例模式出現的目的,操作系統中的應用實例和開發中遇到的幾個場景,我們應該大概知道了什麼時候應該使用單例模式進行開發了。所以單例模式應用的場景一般有兩個條件:
       1、資源共享的情況下,避免由於資源操作時導致的性能或損耗等。如上述中的應用配置、數據連接池的設計。
       2、控制資源的情況下,方便資源之間的互相通信。如多線程的線程池設計等。

      所以,單例模式的適應場景如:
      1、需要頻繁實例化然後銷燬的對象。
      2、創建對象時耗時過多或者耗資源過多,但又經常用到的對象。
      3、有狀態的工具類對象。
      4、頻繁訪問數據庫或文件的對象

單例模式包含(懶漢式和餓漢式)

使用場景區別:
 如果單件模式實例在系統中經常會被用到,餓漢式是一個不錯的選擇。
 反之如果單件模式在系統中會很少用到或者幾乎不會用到,那麼懶漢式是一個不錯的選擇。

單例模式(懶漢式)

懶漢式 當程序第一次訪問單件模式實例時才進行創建。

在懶漢式寫法中, 我們需要非常注意線程同步的問題. 大概有一下幾個: 
1. getInstance() 直接鎖方法好不好 
2. 雙重鎖定 
3. synchronized(this)行不行

1. getInstance() 直接鎖方法好不好

這種寫法:

class Singleton {
    private static Singleton instance;
    private Singleton(){}

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

我們可以看到這裏synchronized是鎖方法, 當兩個線程都要進入getInstance()時, 只有一個能進入, 並創建出實例, 然後另外一個進入後, 判斷 instace不爲null, 然後直接得到instance. 這種做法是沒有錯誤的. 但是由於線程都需要通過getInstance()來獲取對象, 所以getInstance()調用頻率很高, 所以線程被鎖的頻率也很高, 所以這種做法效率低.

2. 雙重鎖定

由於上面效率的原因, 你可能就會想到把 syschronized 放在 getInstance()裏面, 這種可避免在調用getInstance()時的阻塞問題, 如下:

class Singleton {
    private static Singleton instance;
    private Singleton(){}

    public static Singleton getInstance(){
        if(instance == null){
            synchronized(Singleton.class){
                instance = new Singleton();
            }
        }
        return instance;
    }
}

這種寫法看似沒有問題, 其實卻有一個很大的隱患, 在於: 如果兩個線程同時執行getInstance(),判斷 instance都不爲null後, 進入if判斷語句. 這個時候一個線程獲得鎖, 然後進入new了一個對象, 並開心的執行完了. 這個時候另外一個線程獲得了鎖, 但讓它也不會再去判斷 instace是否爲null, 所以它也會再執行一次new操作. 所以這裏執行了兩次new操作. 當然最後instance還是隻指向後一次new的對象. 
所以這個時候需要雙重鎖定, 就是在 synchronized中再加一次 null判斷, 如下:

//懶漢式-雙重檢驗鎖-線程安全
class Singleton3 {
	private static  Singleton3 singleton;
	
	private Singleton3(){}
	
	public static Singleton3 getInstance(){
		if(singleton==null){// 第一步檢驗鎖
			synchronized (Singleton3.class) {
				if(singleton==null){// 第二步檢驗鎖
					singleton = new Singleton3();
				}
			}
		}
		return singleton;
	}
	  
}

這樣就可以保證不會new兩次, 也是相對比較正確的, 並且效率也很高.

3. synchronized(this)行不行

答案是不行的, 如果你寫代碼看一看, 直接就提示語法錯誤了, 因爲我們的 getInstance() 方法是 static的, 所以裏面不能使用 this.

單例模式(餓漢式)

餓漢式 在程序啓動或單件模式類被加載的時候,單件模式實例就已經被創建。

代碼如下:

//餓漢式
class Singleton1 {
	private static  Singleton1 singleton= new Singleton1();
	
	private Singleton1(){}
	
	public static Singleton1 getInstance(){
		return singleton;
	}
	  
}

單例鎖理解:https://www.cnblogs.com/huansky/p/8869888.html

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