中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中如何實現雙重檢查鎖

發布時間:2021-09-14 17:30:50 來源:億速云 閱讀:110 作者:小新 欄目:開發技術

這篇文章主要介紹了Java中如何實現雙重檢查鎖,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

    前言

    在實現單例模式時,如果未考慮多線程的情況,就容易寫出下面的錯誤代碼:

    public class Singleton {
        private static Singleton uniqueSingleton;
    
        private Singleton() {
        }
    
        public Singleton getInstance() {
            if (null == uniqueSingleton) {
                uniqueSingleton = new Singleton();
            }
            return uniqueSingleton;
        }
    }

    在多線程的情況下,這樣寫可能會導致uniqueSingleton有多個實例。比如下面這種情況,考慮有兩個線程同時調用getInstance():

    TimeThread AThread B
    T1檢查到uniqueSingleton為空
    T2
    檢查到uniqueSingleton為空
    T3
    初始化對象A
    T4
    返回對象A
    T5初始化對象B
    T6返回對象B

    可以看到,uniqueSingleton被實例化了兩次并且被不同對象持有。完全違背了單例的初衷。

    加鎖

    出現這種情況,第一反應就是加鎖,如下:

    public class Singleton {
        private static Singleton uniqueSingleton;
    
        private Singleton() {
        }
    
        public synchronized Singleton getInstance() {
            if (null == uniqueSingleton) {
                uniqueSingleton = new Singleton();
            }
            return uniqueSingleton;
        }
    }

    這樣雖然解決了問題,但是因為用到了synchronized,會導致很大的性能開銷,并且加鎖其實只需要在第一次初始化的時候用到,之后的調用都沒必要再進行加鎖。

    雙重檢查鎖

    雙重檢查鎖(double checked locking)是對上述問題的一種優化。先判斷對象是否已經被初始化,再決定要不要加鎖。

    錯誤的雙重檢查鎖

    public class Singleton {
        private static Singleton uniqueSingleton;
    
        private Singleton() {
        }
    
        public Singleton getInstance() {
            if (null == uniqueSingleton) {
                synchronized (Singleton.class) {
                    if (null == uniqueSingleton) {
                        uniqueSingleton = new Singleton();   // error
                    }
                }
            }
            return uniqueSingleton;
        }
    }

    如果這樣寫,運行順序就成了:

    • 檢查變量是否被初始化(不去獲得鎖),如果已被初始化則立即返回。

    • 獲取鎖。

    • 再次檢查變量是否已經被初始化,如果還沒被初始化就初始化一個對象。

    執行雙重檢查是因為,如果多個線程同時了通過了第一次檢查,并且其中一個線程首先通過了第二次檢查并實例化了對象,那么剩余通過了第一次檢查的線程就不會再去實例化對象。

    這樣,除了初始化的時候會出現加鎖的情況,后續的所有調用都會避免加鎖而直接返回,解決了性能消耗的問題。

    隱患

    上述寫法看似解決了問題,但是有個很大的隱患。實例化對象的那行代碼(標記為error的那行),實際上可以分解成以下三個步驟:

    1. 分配內存空間

    2. 初始化對象

    3. 將對象指向剛分配的內存空間

    但是有些編譯器為了性能的原因,可能會將第二步和第三步進行重排序,順序就成了:

    1. 分配內存空間

    2. 將對象指向剛分配的內存空間

    3. 初始化對象

    現在考慮重排序后,兩個線程發生了以下調用:

    TimeThread AThread B
    T1檢查到uniqueSingleton為空
    T2獲取鎖
    T3再次檢查到uniqueSingleton為空
    T4為uniqueSingleton分配內存空間
    T5將uniqueSingleton指向內存空間
    T6
    檢查到uniqueSingleton不為空
    T7
    訪問uniqueSingleton(此時對象還未完成初始化)
    T8初始化uniqueSingleton

    在這種情況下,T7時刻線程B對uniqueSingleton的訪問,訪問的是一個初始化未完成的對象。

    正確的雙重檢查鎖

    public class Singleton {
        private volatile static Singleton uniqueSingleton;
    
        private Singleton() {
        }
    
        public Singleton getInstance() {
            if (null == uniqueSingleton) {
                synchronized (Singleton.class) {
                    if (null == uniqueSingleton) {
                        uniqueSingleton = new Singleton();
                    }
                }
            }
            return uniqueSingleton;
        }
    }

    為了解決上述問題,需要在uniqueSingleton前加入關鍵字volatile。使用了volatile關鍵字后,重排序被禁止,所有的寫(write)操作都將發生在讀(read)操作之前。

    至此,雙重檢查鎖就可以完美工作了。

    感謝你能夠認真閱讀完這篇文章,希望小編分享的“Java中如何實現雙重檢查鎖”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    新干县| 晋中市| 特克斯县| 固原市| 图片| 长宁县| 武义县| 巧家县| 虞城县| 芒康县| 泰兴市| 堆龙德庆县| 平和县| 卢氏县| 博客| 法库县| 大冶市| 三台县| 阿城市| 浮梁县| 兴安县| 荆门市| 红原县| 湘乡市| 微山县| 屯留县| 平顺县| 美姑县| 东平县| 西吉县| 华蓥市| 松原市| 泾阳县| 九台市| 大理市| 辽中县| 青川县| 墨玉县| 常山县| 大渡口区| 马公市|