您好,登錄后才能下訂單哦!
這篇文章主要介紹了Java怎么實現雙重校驗鎖單例的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Java怎么實現雙重校驗鎖單例文章都會有所收獲,下面我們一起來看看吧。
Java代碼實現如下:
//雙重校驗鎖單例 public class SingleInstance { //必須volatile修飾 見分析1 private volatile static SingleInstance instance; //私有化構造函數 private SingleInstance() { } public static SingleInstance getInstance() { //第一個判空 見分析2 if (instance == null) { synchronized (SingleInstance.class) { //第二個判空 見分析3 if (instance == null) { //新建實例 instance = new SingleInstance(); } } } return instance; } }
首先這里synchronized關鍵字沒有修飾整個getInstance函數,因為這個函數可能使用地方很多,這樣就會造成其他線程阻塞,不太好,所以這里只同步了一段代碼。
分析2:為什么在進入同步代碼塊時需要進行進行判空,假如有線程A和線程B,這時線程A先判斷instance為null,所以它進入了同步代碼塊,創建了對象,然后線程B再進來時,它就不必再進入同步代碼快了,可以直接返回,也其實也就是懶加載,可以加快執行速度。
分析3:為什么在同步代碼塊中還要再進行一次判斷呢,假如有線程A和線程B,它倆A先調用方法,B緊接著調用,這時A、B在分析2出的判空都是空,所以A進入同步代碼塊,B進行等待,當A進入同步代碼塊中創建了對象后,A線程釋放了鎖,這時B再進入,如果這時不加分析3的判空,B又會創建一個實例,這明顯不符合規矩。
分析1:那既然加了2層判斷,那為什么還要加個volatile關鍵字呢,這里知識點就有點多了。
因為新建實例的代碼:
instance = new SingleInstance();
它不是一個原子操作,這個簡單的賦值可以分為3步:
1、給SingleInstance分配內存
2、調用SingleInstance的構造方法
3、把instance指向分配的內存空間
這是正常邏輯的3個步驟,也只有按1 2 3執行后,這個instance才不是null。
但是Java內存模型允許這個進行指令重排序,也就是這3步可能是123也可能是132,所以這里就有問題了。
假如線程A和線程B,線程A已經跑到分析3處的代碼,這時這條指令執行是132,剛把步驟3執行完,這時線程B跑到了分析1處的代碼,會發現instance不為null了,這時線程B就直接返回了,從而導致錯誤。
既然知道了原因,那volatile關鍵字就是解決這個的,它可以禁止指令重新排序,而且保證所有線程看到這個變量是一致的,也就是不會從緩存中讀取(這個特性后面有機會再說),所以在創建instance實例時,它的步驟都是123,就不會出錯了。
關于“Java怎么實現雙重校驗鎖單例”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Java怎么實現雙重校驗鎖單例”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。