23種設計模式 - 單例模式
23種設計模式 - 單例模式
1.關於單例模式的一些說明
單例模式:確保一個類最多隻有一個例項,提供一個全域性訪問點
注意:
-
單例類只能有一個例項
-
單例類必須自己建立自己的唯一例項
-
單例類必須給所有其他物件提供這一例項
單例模式可以分為兩種:預載入和懶載入(即餓漢式和懶漢式)
2.兩種形式詳解
1.預載入(餓漢式)
預先載入。還沒有使用該單例物件,但是該單例物件就已被載入到記憶體。
若沒有使用該單例物件,該物件就被載入到了記憶體,會造成記憶體的浪費。
2.懶載入(懶漢式)
為了避免記憶體的浪費,可以採用懶載入,即用到該單例物件的時候再建立。
3. 單例模式和執行緒安全
-
餓漢式只有一條語句return instance,可以保證執行緒安全。但會造成記憶體的浪費;
-
懶漢式不浪費記憶體,但是無法保證執行緒的安全。首先,if判斷以及其記憶體執行程式碼是非原子性的。其次,new Singleton()無法保證執行的順序性。不滿足原子性或者順序性,執行緒肯定是不安全的,不再贅述;
-
為什麼new Singleton()無法保證順序性。建立一個物件分三步:
JVM為了提高程式執行效能,會對沒有依賴關係的程式碼進行重排序,上面2和3行程式碼可能被重新排序。我們用兩個執行緒來說明執行緒是不安全的。執行緒A和執行緒B都建立物件。其中,A2和A3的重排序,將導致執行緒B在B1處判斷出instance不為空,執行緒B接下來將訪問instance引用的物件。此時,執行緒B將會訪問到一個還未初始化的物件(執行緒不安全)。
4. 懶漢式的執行緒安全解決方法
使用synchronized關鍵字。synchronized載入getInstace()函式上確實保證了執行緒的安全。
Synchronized是Java多執行緒程式設計中最常用的關鍵字。所有的Java 物件都有自己唯一的隱式同步鎖。該鎖只能同時被一個執行緒獲得,其他試圖獲得該鎖的執行緒都會被阻塞在物件的等待佇列中直到獲得該鎖的執行緒釋放鎖才能繼續工作。
注意:若要經常的呼叫getInstance()方法,不管有沒有初始化例項,都會喚醒和阻塞執行緒。為了避免執行緒的上下文切換消耗大量時間,如果物件已經例項化了,我們沒有必要再使用synchronized加鎖,直接返回物件。
把sychronized加在if(instance==null)判斷語句裡面,保證instance未例項化的時候才加鎖。
new一個物件的程式碼是無法保證順序性的,需要使用關鍵字volatile保證物件例項化過程的順序性。
即保證了懶漢式的執行緒安全。
Java極客思維
微信掃一掃,關注公