設計模式系列 - 單例模式

是什么?
定義: 確保一個類只有一個實體,并且提供訪問該實體的靜態方法,
單例的特點:
- 在JVM中有且只能有一個實體存在,
- 構造器必須私有(
private修飾),禁止外部類通過構造器創建, - 提供一個全域公開的
getInstance()方法獲取該實體,
餓漢式 - 執行緒安全
餓漢式,簡單理解就是比較餓,事先就迫不及待創建好實體, 然后呼叫 get 方法的時候,直接回傳該實體即可,
直接創建:

靜態代碼塊創建:

因為是事先創建好實體,所以沒有執行緒安全問題,
懶漢式 - 執行緒不安全
懶漢式,可以理解為它懶,只有到真正要用到實體的時候,它才會去創建,
簡單實作 ~~

這種寫法會有會有執行緒問題, 如果多個執行緒都執行到 if(lhSingleton == null) 并且通過,那么就會創建多個實體,
要解決這個問題也簡單,給 getInstance() 方法加鎖就行了,保證同一時刻只有一個執行緒獲取實體,即可,說干就干 ~~

這樣是比較干脆的解決了執行緒安全問題,
這樣做有個缺點,就是已經有實體了,每次呼叫還是要加鎖排隊,極大的影響性能,不推薦這樣寫,
我們要做到,只有最開始需要創建實體的時候,才加鎖同步,那繼續優化吧 ~~ 也就是雙檢鎖了!
雙檢鎖 - 執行緒安全

- 先檢查實體是否已存在,不存在才加鎖
- 考慮到有多個執行緒會通過第一次的判斷, 即使加了鎖,這些執行緒依舊會排隊執行同步代碼塊中的創建實體邏輯,還是可能會創建多次的,所以需要在同步代碼塊種進行二次判斷,
sjsSingleton 采用 volatile 關鍵字修飾也是很有必要的, sjsSingleton = new SJSSingleton();這段代碼其實分為三步執行:
- 為 sjsSingleton 實體在堆中分配記憶體空間
- 初始化 sysSingleton
- 將 jssSingleton 指向分配的記憶體地址
但是由于 JVM 具有指令重排序的特性,執行順序可能變成1>3>2,指令重排在單執行緒環境下不會出現問題,但是在多執行緒環境下,會導致一個執行緒獲得還沒有初始化的實體,
使用 volatile 可以禁止 JVM 指令重排, 保證在多執行緒環境下也能正常運行,
volatile 除了禁止JVM 指令重排之外,還可以保證變數記憶體可見性,想具體了解,可以去查看相關資料!
本文由博客一文多發平臺 OpenWrite 發布!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/341686.html
標籤:Java
