單例模式介紹及其執行緒安全問題

2022-09-16 20:57:27 字數 2018 閱讀 2136

介紹下單例模式,即保證對乙個類只例項化乙個物件。實際生產例子有,spring的bean預設建立模式等。

一.餓漢式單例(執行緒安全)

缺點:直接例項化,資源會浪費。丟失了延遲例項化的效能好處。

二.懶漢式單例(執行緒不安全)

缺點:執行緒不安全,如果多個執行緒能夠同時進入if (instance == null),並且此時 instance 為 null,那麼會有多個執行緒執行 instance = new lazysingleton();語句,這將導致例項化多次物件。即此類不是單例了。

三.執行緒安全的懶漢式單例例子。

1>  對 getinstance() 方法加鎖,那麼在乙個時間點只能有乙個執行緒能夠進入該方法,從而避免了例項化多次 uniqueinstance。

2>雙重校驗鎖。先判斷 instance 是否已經被例項化,如果沒有被例項化,那麼才對例項化語句進行加鎖

缺點:基本無缺點,除了第一次例項化的時候會加鎖,可能會有執行緒堵塞。

如果兩個執行緒都執行了 if 語句,那麼兩個執行緒都會進入 if 語句塊內。雖然在 if 語句塊內有加鎖操作,但是兩個執行緒都會執行instance = new singleton();這條語句,只是先後的問題,那麼就會進行兩次例項化。因此必須使用雙重校驗鎖,也就是需要使用兩個 if 語句。

instance 採用 volatile 關鍵字修飾也是很有必要的。volatile的作用是1.記憶體可見性: 所有執行緒都能看到共享記憶體的最新狀態  2.防止指令重排。 (volatile修飾的變數並不是原子變數。只是變數的讀和寫變成了原子操作)

instance= new lazysingleton();這段**其實是分為三步執行:

為 instance 分配記憶體空間

初始化 instance 

將 instance 指向分配的記憶體位址

但是由於 jvm 具有指令重排的特性,執行順序有可能變成 1>3>2。指令重排在單執行緒環境下不會出現問題,但是在多執行緒環境下會導致乙個執行緒獲得還沒有初始化的例項。例如,執行緒 t1 執行了 1 和 3,此時 t2 呼叫 getinstance() 後發現 instance 不為空,因此返回 instance ,但此時 instance 還未被初始化。

使用 volatile 可以禁止 jvm 的指令重排,保證在多執行緒環境下也能正常執行。

3>靜態內部類實現。具有延遲初始化的好處,而且由 jvm 提供了對執行緒安全的支援。

內部靜態類的變數並不會在類載入的時候就初始化好,而是會在呼叫的時候才初始化。保證資源的節約。

單例模式及執行緒安全問題

單例模式是為確保乙個類只有乙個例項,並為整個系統提供乙個全域性訪問點的一種模式方法。從概念中體現出了單例的一些特點 1 在任何情況下,單例類永遠只有乙個例項存在 2 單例需要有能力為整個系統提供這一唯一例項 下面是實現 package org.mlinge.s02 public class mysi...

單例模式的執行緒安全問題

單例會帶來什麼問題?如果多個執行緒同時呼叫這個例項,會有執行緒安全的問題 單例一般用在什麼地方?單例的目的是為了保證執行時只有唯一的乙個例項,最常用的地方比如拿到資料庫的連線,或者spring的中建立beanfactory操作,而這些操作都是呼叫他們的方法來執行某個特定的動作。首先先來認識下兩種模式...

單例模式和執行緒安全問題

單例模式是一種常用的軟體設計模式,其定義是單例物件的類只能允許乙個例項存在。許多時候整個系統只需要擁有乙個的全域性物件,這樣有利於我們協調系統整體的行為。比如在某個伺服器程式中,該伺服器的配置資訊存放在乙個檔案中,這些配置資料由乙個單例物件統一讀取,然後服務程序中的其他物件再通過這個單例物件獲取這些...