最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中雙重檢查鎖(double checked locking)的正確實(shí)現(xiàn)

 更新時(shí)間:2021年09月14日 15:25:01   作者:Decouple  
雙重檢查鎖(Double-Check Locking),顧名思義,通過兩次檢查,并基于加鎖機(jī)制,實(shí)現(xiàn)某個(gè)功能,下面這篇文章主要給大家介紹了關(guān)于Java中雙重檢查鎖(double checked locking)的相關(guān)資料,需要的朋友可以參考下

前言

在實(shí)現(xiàn)單例模式時(shí),如果未考慮多線程的情況,就容易寫出下面的錯(cuò)誤代碼:

public class Singleton {
    private static Singleton uniqueSingleton;

    private Singleton() {
    }

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

在多線程的情況下,這樣寫可能會(huì)導(dǎo)致uniqueSingleton有多個(gè)實(shí)例。比如下面這種情況,考慮有兩個(gè)線程同時(shí)調(diào)用getInstance():

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

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

加鎖

出現(xiàn)這種情況,第一反應(yīng)就是加鎖,如下:

public class Singleton {
    private static Singleton uniqueSingleton;

    private Singleton() {
    }

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

這樣雖然解決了問題,但是因?yàn)橛玫搅藄ynchronized,會(huì)導(dǎo)致很大的性能開銷,并且加鎖其實(shí)只需要在第一次初始化的時(shí)候用到,之后的調(diào)用都沒必要再進(jìn)行加鎖。

雙重檢查鎖

雙重檢查鎖(double checked locking)是對上述問題的一種優(yōu)化。先判斷對象是否已經(jīng)被初始化,再?zèng)Q定要不要加鎖。

錯(cuò)誤的雙重檢查鎖

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;
    }
}

如果這樣寫,運(yùn)行順序就成了:

  • 檢查變量是否被初始化(不去獲得鎖),如果已被初始化則立即返回。
  • 獲取鎖。
  • 再次檢查變量是否已經(jīng)被初始化,如果還沒被初始化就初始化一個(gè)對象。

執(zhí)行雙重檢查是因?yàn)?,如果多個(gè)線程同時(shí)了通過了第一次檢查,并且其中一個(gè)線程首先通過了第二次檢查并實(shí)例化了對象,那么剩余通過了第一次檢查的線程就不會(huì)再去實(shí)例化對象。

這樣,除了初始化的時(shí)候會(huì)出現(xiàn)加鎖的情況,后續(xù)的所有調(diào)用都會(huì)避免加鎖而直接返回,解決了性能消耗的問題。

隱患

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

  1. 分配內(nèi)存空間
  2. 初始化對象
  3. 將對象指向剛分配的內(nèi)存空間

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

  1. 分配內(nèi)存空間
  2. 將對象指向剛分配的內(nèi)存空間
  3. 初始化對象

現(xiàn)在考慮重排序后,兩個(gè)線程發(fā)生了以下調(diào)用:

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

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

正確的雙重檢查鎖

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前加入關(guān)鍵字volatile。使用了volatile關(guān)鍵字后,重排序被禁止,所有的寫(write)操作都將發(fā)生在讀(read)操作之前。

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

總結(jié)

到此這篇關(guān)于Java中雙重檢查鎖(double checked locking)的文章就介紹到這了,更多相關(guān)Java雙重檢查鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

參考資料:

相關(guān)文章

  • Java中通過反射實(shí)現(xiàn)代理Proxy代碼實(shí)例

    Java中通過反射實(shí)現(xiàn)代理Proxy代碼實(shí)例

    這篇文章主要介紹了Java中通過反射實(shí)現(xiàn)代理Proxy代碼實(shí)例,java實(shí)現(xiàn)代理可以通過java.lang.reflect.Proxy接口結(jié)合java.lang.reflect.InvocationHandler來實(shí)現(xiàn),需要的朋友可以參考下
    2023-08-08
  • springBoot中的properties配置解析

    springBoot中的properties配置解析

    這篇文章主要介紹了springBoot中的properties配置解析,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • java配置數(shù)據(jù)庫連接池的方法步驟

    java配置數(shù)據(jù)庫連接池的方法步驟

    java配置數(shù)據(jù)庫連接池的方法步驟,需要的朋友可以參考一下
    2013-05-05
  • Java中構(gòu)造器內(nèi)部的多態(tài)方法的行為實(shí)例分析

    Java中構(gòu)造器內(nèi)部的多態(tài)方法的行為實(shí)例分析

    這篇文章主要介紹了Java中構(gòu)造器內(nèi)部的多態(tài)方法的行為,結(jié)合實(shí)例形式分析了java構(gòu)造器內(nèi)部多態(tài)方法相關(guān)原理、功能及操作技巧,需要的朋友可以參考下
    2019-10-10
  • SpringBoot使用@EnableAutoConfiguration實(shí)現(xiàn)自動(dòng)配置詳解

    SpringBoot使用@EnableAutoConfiguration實(shí)現(xiàn)自動(dòng)配置詳解

    你有想過SpringBoot為什么能夠自動(dòng)的幫我們創(chuàng)建一個(gè)Bean對象么?或許在我們使用的時(shí)候只需要在自己自定義的配置文件中加入@Bean對象就可以,但SpringBoot是如何來創(chuàng)建的呢
    2022-08-08
  • springboot ehcache 配置使用方法代碼詳解

    springboot ehcache 配置使用方法代碼詳解

    EhCache是一個(gè)比較成熟的Java緩存框架,Springboot對ehcache的使用非常支持,所以在Springboot中只需做些配置就可使用,且使用方式也簡易,今天給大家分享springboot ehcache 配置使用教程,一起看看吧
    2021-06-06
  • Java中使用增強(qiáng)for循環(huán)的實(shí)例方法

    Java中使用增強(qiáng)for循環(huán)的實(shí)例方法

    在本篇文章里小編給大家整理是的關(guān)于Java中如何使用增強(qiáng)for循環(huán)的實(shí)例內(nèi)容以及相關(guān)代碼,需要的朋友們可以學(xué)習(xí)下。
    2019-08-08
  • Java線程三種命名方法詳解

    Java線程三種命名方法詳解

    這篇文章主要介紹了Java線程三種命名方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • java分治思想之ForkJoin詳解

    java分治思想之ForkJoin詳解

    這篇文章主要為大家介紹了java分治思想之ForkJoin使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Java發(fā)送https請求并跳過ssl證書驗(yàn)證方法

    Java發(fā)送https請求并跳過ssl證書驗(yàn)證方法

    最近在負(fù)責(zé)一個(gè)對接第三方服務(wù)的事情,在對接期間因?yàn)榈谌椒?wù)為https的請求,這篇文章主要給大家介紹了關(guān)于Java發(fā)送https請求并跳過ssl證書驗(yàn)證的相關(guān)資料,需要的朋友可以參考下
    2023-11-11

最新評論

依兰县| 江都市| 宜昌市| 三门峡市| 金平| 长顺县| 桂林市| 酒泉市| 青阳县| 贞丰县| 丰台区| 房产| 中卫市| 台湾省| 屯昌县| 龙州县| 拉孜县| 石林| 大余县| 孟津县| 陆良县| 丹寨县| 灵璧县| 淮滨县| 辽源市| 腾冲县| 信阳市| 出国| 泸西县| 乐昌市| 溆浦县| 五大连池市| 金湖县| 迭部县| 青田县| 柯坪县| 岱山县| 南华县| 焉耆| 盐池县| 东至县|