單例模式與執行緒安全

2021-09-01 05:16:36 字數 2282 閱讀 3646

請看如下的單例類:

class singleton

return singleton;

}

首先判斷singleton是否為null,如果是就建立singleton物件,否則直接返回singleton。但是判斷和建立並非原子操作,假設執行緒1正在執行null == singleton,判斷為true,準備執行下一句new singleton();此時執行緒2可能已經new了乙個 singleton了,執行緒1再次new了乙個singleton,出現2個singleton與單例的設計思想不符,即單例的控制在併發情況下失效了,測試**可直觀的反應該問題:

public class mythread extends thread 

public static void main(string args)

}}class singleton

return singleton;

}}

輸出:

singleton@69b332

singleton@69b332

singleton@69b332

singleton@69b332

singleton@173a10f

singleton@69b332

singleton@69b332

singleton@69b332

singleton@69b332

singleton@69b332

可以在getsingleton方法前加synchronized,確保任意時刻都只有乙個執行緒可以進入該方法。但是這樣一來,會降低整個訪問的速度,而且每次都要判斷。

可以使用"雙重檢查加鎖"的方式來實現,就可以既實現執行緒安全,又能夠使效能不受到很大的影響。

public class singleton   

public static singleton getinstance()

} }

return instance;

} }

所謂雙重檢查加鎖機制,指的是:並不是每次進入getinstance方法都需要同步,而是先不同步,進入方法過後,先檢查例項是否存在,如果不存 在才進入下面的同步塊,這是第一重檢查。進入同步塊過後,再次檢查例項是否存在,如果不存在,就在同步的情況下建立乙個例項,這是第二重檢查。這樣一來, 就只需要同步一次了,從而減少了多次在同步情況下進行判斷所浪費的時間。

雙重檢查加鎖機制的實現會使用乙個關鍵字volatile,它的意思是:被volatile修飾的變數的值,將不會被本地執行緒快取,所有對該變數的讀寫都是直接操作共享記憶體,從而確保多個執行緒能正確的處理該變數。

雙重檢查機制,盡可能縮小了同步塊的範圍。

這裡解釋一下為什麼要判斷2次,當兩個執行緒呼叫getinstance方法時,它們都將通過第一重instance==null的判斷,由於同步機制,這2個執行緒只能有乙個進入,另乙個排隊。而此時如果沒有第二重判斷,則第乙個執行緒建立了例項,而第二個例項離開佇列重新獲得鎖,則將繼續建立例項,這樣就沒有達到單例的目的。

在多執行緒開發中,為了解決併發問題,主要是通過使用synchronized來加互斥鎖進行同步控制。但是在某些情況中,jvm已經隱含地為您執行了同步,這些情況下就不用自己再來進行同步控制了。這些情況包括:

由靜態初始化器(在靜態欄位上或 static{} 塊中的初始化器)初始化資料時

訪問 final 欄位時

在建立執行緒之前建立物件時

執行緒可以看見它將要處理的物件時。

一種可行的方式就是採用類級內部類,在這個類級內部類裡面去建立物件例項。這樣一來,只要不使用到這個類級內部類,那就不會建立物件例項,從而同時實現延遲載入和執行緒安全。

看看**示例可能會更清晰一些,示例**如下:

public class singleton   

/**

* 私有化構造方法

*/

private singleton()

public static singleton getinstance()

}

當getinstance方法第一次被呼叫的時候,它第一次讀取singletonholder.instance,導致 singletonholder類得到初始化;而這個類在裝載並被初始化的時候,會初始化它的靜態域,從而建立singleton的例項,由於是靜態的 域,因此只會在虛擬機器裝載類的時候初始化一次,並由虛擬機器來保證它的執行緒安全性。

這個模式的優勢在於,getinstance方法並沒有被同步,並且只是執行乙個域的訪問,因此延遲初始化並沒有增加任何訪問成本

單例模式與執行緒安全

在類載入的時候,就已經進行例項化,無論之後用不用到。如果該模擬較佔記憶體,之後又沒用到,就白白浪費了資源。public class hungersingleton private hungersingleton public static void main string args start 在需...

單例模式與執行緒安全

概念 單例模式確保某個類只有乙個例項,而且自行例項化並向整個系統提供這個例項。在計算機系統中,執行緒池 快取 日誌物件 對話方塊 印表機 顯示卡的驅動程式物件常被設計成單例。這些應用都或多或少具有資源管理器的功能。每台計算機可以有若干個印表機,但只能有乙個printer spooler,以避免兩個列...

單例模式與執行緒安全單例模式(懶漢 餓漢)

直接就可以在靜態區初始化instance,然後通過getinstance返回,這種就被稱為餓漢式單例類。也有些寫法是在getinstance中new instance然後返回,這種就被稱為懶漢式單例類,但這涉及到第一次getinstance的乙個判斷問題。單例大約有兩種實現方法 懶漢與餓漢。懶漢 故...