請看如下的單例類:
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的乙個判斷問題。單例大約有兩種實現方法 懶漢與餓漢。懶漢 故...