線程安全的單例模式

面試的時候,常常會被問到這樣一個問題:請您寫出一個單例模式(Singleton Pattern)吧。好吧,寫就寫,這還不容易。順手寫一個:
  1. public?final?class?EagerSingleton ?
  2. {??
  3. ????private?static?EagerSingleton?singObj?=?new?EagerSingleton();??
  4. ??
  5. ????private?EagerSingleton(){ ?
  6. ????}??
  7. ??
  8. ????public?static?EagerSingleton?getSingleInstance(){ ?
  9. ???????return?singObj;
  10. ????}??
  11. } ?
這種寫法就是所謂的?饑餓模式,每個對象在沒有使用之前就已經初始化了。這就可能帶來潛在的性能問題:如果這個對象很大呢?沒有使用這個對象之前,就把它加載到了內存中去是一種巨大的浪費。針對這種情況,我們可以對以上的代碼進行改進,使用一種新的設計思想——?延遲加載(Lazy-load Singleton)。
  1. public?final?class?LazySingleton ?
  2. {??
  3. ????private?static?LazySingleton?singObj?=?null;??
  4. ??
  5. ????private?LazySingleton(){ ?
  6. ????}??
  7. ??
  8. ????public?static?LazySingleton?getSingleInstance(){ ?
  9. ????????if(null?==?singObj?)?singObj = new LazySingleton();
  10. ??????????return?singObj;
  11. ????}??
  12. } ?
這種寫法就是所謂的?懶漢模式。它使用了延遲加載來保證對象在沒有使用之前,是不會進行初始化的。但是,通常這個時候面試官又會提問新的問題來刁難一下。他會問:這種寫法線程安全嗎?回答必然是:不安全。這是因為在多個線程可能同時運行到第九行,判斷singObj為null,于是同時進行了初始化。所以,這是面臨的問題是如何使得這個代碼線程安全?很簡單,在那個方法前面加一個Synchronized就OK了。
  1. public?final?class?ThreadSafeSingleton ?
  2. {??
  3. ????private?static?ThreadSafeSingleton?singObj?=?null;??
  4. ??
  5. ????private?ThreadSafeSingleton(){ ?
  6. ????}??
  7. ??
  8. ????public?static?Synchronized?ThreadSafeSingleton?getSingleInstance(){ ?
  9. ????????if(null?==?singObj?)?singObj = new?ThreadSafeSingleton();
  10. ????????????return?singObj;
  11. ????}??
  12. } ?
寫到這里,面試官可能仍然會狡猾的看了你一眼,繼續刁難到:這個寫法有沒有什么性能問題呢?答案肯定是有的!?同步的代價必然會一定程度的使程序的并發度降低。那么有沒有什么方法,一方面是線程安全的,有可以有很高的并發度呢?我們觀察到,線程不安全的原因其實是在初始化對象的時候,所以,可以想辦法把同步的粒度降低,只在初始化對象的時候進行同步。這里有必要提出一種新的設計思想——?雙重檢查鎖(Double-Checked Lock)。
  1. public?final?class?DoubleCheckedSingleton ?
  2. {??
  3. ????private?static?DoubleCheckedSingletonsingObj?=?null;??
  4. ??
  5. ????private?DoubleCheckedSingleton(){ ?
  6. ????}??
  7. ??
  8. ????public?static?DoubleCheckedSingleton?getSingleInstance(){ ?
  9. ????????if(null?==?singObj?) {
  10. ??????????????Synchronized(DoubleCheckedSingleton.class){
  11. ?????????????????????if(null?==?singObj)
  12. ???????????????????????????singObj = new?DoubleCheckedSingleton();
  13. ??????????????}
  14. ?????????}
  15. ???????return?singObj;
  16. ????}??
  17. } ?
這種寫法使得只有在加載新的對象進行同步,在加載完了之后,其他線程在第九行就可以判斷跳過鎖的的代價直接到第15行代碼了。做到很好的并發度。
至此,上面的寫法一方面實現了Lazy-Load,另一個方面也做到了并發度很好的線程安全,一切看上很完美。這是,面試官可能會對你的回答滿意的點點頭。但是,你此時提出說,其實這種寫法還是有問題的!!問題在哪里?假設線程A執行到了第9行,它判斷對象為空,于是線程A執行到第12行去初始化這個對象,但初始化是需要耗費時間的,但是這個對象的地址其實已經存在了。此時線程B也執行到了第九行,它判斷不為空,于是直接跳到15行得到了這個對象。但是,這個對象還?沒有被完整的初始化!得到一個沒有初始化完全的對象有什么用!!關于這個Double-Checked Lock的討論有很多,目前公認這是一個Anti-Pattern,不推薦使用!所以當你的面試官聽到你的這番答復,他會不會被Hold住呢?
那么有沒有什么更好的寫法呢?有!這里又要提出一種新的模式——?Initialization on Demand Holder.?這種方法使用內部類來做到延遲加載對象,在初始化這個內部類的時候,JLS(Java Language Sepcification)會保證這個類的線程安全。這種寫法最大的美在于,完全使用了Java虛擬機的機制進行同步保證,沒有一個同步的關鍵字。
  1. public?class?Singleton ???
  2. {????
  3. ????private?static?class?SingletonHolder????
  4. ????{????
  5. ????????public?final?static?Singleton?instance?=?new?Singleton();????
  6. ????}????
  7. ???
  8. ????public?static?Singleton?getInstance()????
  9. ????{????
  10. ????????return?SingletonHolder.instance;????
  11. ????}????
  12. } ?
至此,本文完。提供一些鏈接For your reference:
Double-Checked Lock:?http://en.wikipedia.org/wiki/Double-checked_locking
Initialzation on Demand Holder:??http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
原文地址:http://blog.sina.com.cn/s/blog_75247c770100yxpb.html

轉載于:https://www.cnblogs.com/imsoft/p/6371119.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282910.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282910.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282910.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vue實現首屏加載等待動畫 避免首次加載白屏尷尬

為什么80%的碼農都做不了架構師?>>> 0 直接上效果圖 1背景,用戶體驗良好一直是個重要的問題。 2怎么加到自己項目里面? 復制css html代碼到自己的index.html即可 代碼鏈接 源碼地址 Vue學習前端群493671066,美女多多。…

java-回調機制詳解

轉:http://blog.csdn.net/llayjun/article/details/50454148 閱讀目錄 一、前言二、回調的含義和用途三、Java實現接口回調 四、Android中的接口回調五、參考資料一、前言 最近在看android fragment與Activity進行數據傳遞的部分,看到了接口回調的內容&a…

lfi讀取php,php LFI讀php文件源碼以及直接post webshell

php LFI讀php文件源碼以及間接post 網站shell假如如下一個場景(1) http://vulnerable/fileincl/example1.php?pageintro.php(該php文件包孕LFI漏洞)(2) 然而你不有中央能夠upload你的網站shell代碼(三) LFI只能讀取到非php文件的源碼(由于無…

根據請求上下文動態設置靜態文件存儲目錄

前言上次,我們實現了根據 subpath 特定格式《動態設置靜態文件存儲目錄》。例如:subpath靜態文件路徑/userAId/1.jpgc:\abc\userAId\1.jpg/userBId/1.jpgd:\xyz\123\userBId\1.jpg但是,如果 subpath 不能有這種特定格式,只能用通用…

BZOJ3019 : [Balkan2012]handsome

首先預處理出$f[i][j][k]$表示長度為$i$的序列,第一個位置是$j$,最后一個位置是$k$時合法的方案數。 從后往前枚舉LCP以及那個位置應該改成什么。 用線段樹維護區間內最左最右的已經確定的位置,以及區間內的合法方案數。 合并的時候只需要將左…

php smarty入門,smarty 快速入門

smarty 快速入門smarty定義:一個開源的模板引擎模板引擎是為了使用戶界面與業務數據分離而產生的,它可以生成特定格式的文檔,用于網站的模板引擎就會生成一個標準的HTML文檔。功能將網站的數據和網站的界面實現分離(php和html代碼)緩存頁面下載www.smart…

ImageView的scaleType理解

2019獨角獸企業重金招聘Python工程師標準>>> 1.android:scaleType“center” 保持原圖的大小,顯示在ImageView的中心。當原圖的size大于ImageView的size時,多出來的部分被截掉。 2.android:scaleType“center_inside” 以原圖正常顯示為目的&…

第一章 引論

1、什么是多道程序設計? 即內存中同時運行多道獨立程序,宏觀上所有程序同時運行,微觀上程序串行,多道程序輪流占用CPU,提高了資源利用率。 2、什么是SPOOLING?讀者是否認為將來的高級個人計算機會把SPOOLIN…

《ASP.NET Core 6框架揭秘》實例演示[24]:中間件的多種定義方式

ASP.NET Core的請求處理管道由一個服務器和一組中間件組成&#xff0c;位于 “龍頭” 的服務器負責請求的監聽、接收、分發和最終的響應&#xff0c;針對請求的處理由后續的中間件來完成。中間件最終體現為一個Func<RequestDelegate, RequestDelegate>委托&#xff0c;但…

Android之 RecyclerView,CardView 詳解和相對應的上拉刷新下拉加載

為什么80%的碼農都做不了架構師&#xff1f;>>> 隨著 Google 推出了全新的設計語言 Material Design&#xff0c;還迎來了新的 Android 支持庫 v7&#xff0c;其中就包含了 Material Design 設計語言中關于 Card 卡片概念的實現 —— CardView。RecyclerView也是谷…

php獲取郵箱內容嗎,php正則驗證email郵箱及抽取內容中email的例子

1&#xff0c;php正則驗證email格式&#xff1a;復制代碼 代碼示例:if (ereg(“/^[a-z]([a-z0-9]*[-_\.]?[a-z0-9])*([a-z0-9]*[-_]?[a-z0-9])[\.][a-z]{2,3}([\.][a-z]{2})?$/i; ”,$email)){echo “Your email address is correct!”;}else{echo “Please try again!”;}?…

Java——Arrays類操作數組的工具類

JDK中提供了一個專門用于操作數組的工具類&#xff0c;即 Arrays 類&#xff0c;位于 Java。util 包中。該類提供了一系列方法來操作數組&#xff0c;如排序、復制、比較、填充等&#xff0c;用戶直接調用這些方法即可&#xff0c;不需要自己編碼實現&#xff0c;降低了開發難度…

PropertiesUtil 獲取文件屬性值

有時候不要把一些屬性值寫死在代碼中&#xff0c;而是寫在配置在文件中&#xff0c;方便更改 PropertiesUtil工具類&#xff1a;讀取key-value形式的配置文件&#xff0c;根據key獲得value值 1、測試類 public class Test{private static PropertiesUtil propertiesUtil new …

CORS——跨域請求那些事兒

【本期嘉賓介紹】睿得&#xff0c;具有多年研發、運維、安全等IT相關從業經歷。目前從事CDN、存儲、視頻直播點播的技術支持。喜愛鉆研&#xff0c;喜愛編碼&#xff0c;喜愛分享。 在日常的項目開發時會不可避免的需要進行跨域操作&#xff0c;而在實際進行跨域請求時&#xf…

oracle 數據執行計劃,Oracle里常見的執行計劃

本文介紹了Oracle數據庫里常見的執行計劃&#xff0c;使用的Oracle數據庫版本為11.2.0.1。1、與表訪問相關的執行計劃Oracle數據庫里與表訪問有關的兩種方法&#xff1a;全表掃描和ROWID掃描。反映在執行計劃上&#xff0c;與全表掃描對應的執行計劃中的關鍵字是“TABLE ACCESS…

.NET MAUI實戰 Dispatcher

詳細內容這一期分享的內容非常簡單&#xff0c;在之前使用過WPF的開發者對MVVM開發模式下ViewModel中后臺線程轉UI線程并不陌生使用Appplication.Current.Dispatcher。那么在.NET MAUI中也有同樣的機制&#xff0c;存在于.NET MAUI Shell對象中。那么什么是Shell&#xff1f;官…

GDB 配置

GDB 配置 使用 GDB 擴展來配置 GDB 事實上我還是覺得原生的 GDB 就挺好&#xff0c;速度快&#xff0c;需要查看什么執行命令就可以。 GDB DashBoard https://github.com/cyrus-and/gdb-dashboard $sudo mkdir -m 777 ~/gdbinit; cd ~/gdbinit $git clone https://github.com/c…

Oracle區分中文和英文,oracle中中英文段落劃分實現

oracle中關于中文占用字節數&#xff0c;不同的數據庫有不同的情況&#xff0c;有的占用兩個字節、有的占用三個字節&#xff0c;現在測試環境的數據庫中文占用三個字節&#xff0c;要實現由中英文組成的段落字符串&#xff0c;按照每行占用多少字節重新分段&#xff0c;具體應…

未來哪些行業值得加入?

閱讀本文大概需要5分鐘。這個問題很多讀者都問過&#xff0c;基本上每隔幾篇原創就會有人留言問&#xff0c;還有公眾號后臺和知乎私聊。之前在一次留言中我承諾專門開一篇文章來聊聊這個話題&#xff0c;今天想著要兌現這個諾言了。為啥最近會存在這個問題呢&#xff0c;原因其…

虛擬機網絡配置詳解(NAT、橋接、Hostonly)

VirtualBox中有四種網絡連接方式: NATBridged AdapterInternalHost-only AdapterVMWare中有三種&#xff0c;其實它跟VMWare的網絡連接方式都是一樣的概念&#xff0c;只是比VMWare多了Internal方式 在介紹四種工作模式之前&#xff0c;先說下虛擬網卡&#xff0c;虛擬機安裝好…