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

LongAdder原理及創(chuàng)建使用示例詳解

 更新時(shí)間:2023年01月13日 11:58:13   作者:Afu  
這篇文章主要為大家介紹了LongAdder原理及創(chuàng)建使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

LongAdder介紹

1.Atomic原子類

Atomic的原子類內(nèi)部使用的是CAS原則,CAS是一個(gè)樂觀鎖,但是如果是在高并發(fā)的情況下的話,多個(gè)線程不斷地競(jìng)爭(zhēng)

CAS的不斷的自旋,非常耗CPU.

高并發(fā)環(huán)境下,value變量其實(shí)是一個(gè)熱點(diǎn),也就是多個(gè)線程競(jìng)爭(zhēng)一個(gè)熱點(diǎn)。

這時(shí)候就需要使用的 LongAdder 來(lái)替代 Atomic類

2.LongAdder原理

LongAdder的原理就是分散熱點(diǎn),將value分散到一個(gè)數(shù)組中,不同的線程去找自己的對(duì)應(yīng)的Cell進(jìn)行修改值,

各個(gè)線程對(duì)Cell進(jìn)行CAS操作,這樣熱點(diǎn)就被分散了,沖突的概率小了,性能就提高了.

如果要返回實(shí)際的值,返回所有的數(shù)組中的值和base值就行.

2.查看LongAdder的add方法

public void add(long x) {
    Cell[] as; long b, v; int m; Cell a;
    if ((as = cells) != null || !casBase(b = base, b + x)) {
        boolean uncontended = true;
        if (as == null || (m = as.length - 1) < 0 ||
            (a = as[getProbe() & m]) == null ||
            !(uncontended = a.cas(v = a.value, v + x)))
            longAccumulate(x, null, uncontended);
    }
}

一看到這種代碼就頭皮發(fā)麻

簡(jiǎn)單說(shuō)明一下這幾行代碼作用,說(shuō)多了,你也懶得看

第一個(gè)if作用:

如果還沒有初始化cells數(shù)組,就去修改base值

如果修改Base值失敗,說(shuō)明多個(gè)線程對(duì)base值修改發(fā)生了競(jìng)爭(zhēng)

第二個(gè)if作用:

判斷有沒有cells有沒有值,有的話說(shuō)明已經(jīng)初始化過cells數(shù)組了

知道對(duì)應(yīng)的桶位添加值或者修改值

我感覺你已經(jīng)不知道我在說(shuō)什么了!

反正你就知道,如果有多個(gè)線程發(fā)生了競(jìng)爭(zhēng),就去cells數(shù)組中找對(duì)應(yīng)的桶位的cell添加或者修改值即可

3.longAccumulate方法

這里的代碼特別的惡心,是能助眠的好代碼,建議收藏!

簡(jiǎn)單說(shuō)明一下幾個(gè)核心的代碼

3.1.創(chuàng)建Cell數(shù)組

  else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
                boolean init = false;
                try {
                    if (cells == as) {
                        Cell[] rs = new Cell[2];
                        rs[h & 1] = new Cell(x);
                        cells = rs;
                        init = true;
                    }
                } finally {
                    cellsBusy = 0;
                }
                if (init)
                    break;
            }

Cell數(shù)組還沒有進(jìn)行初始化,

創(chuàng)建長(zhǎng)度為2的Cell數(shù)組

在索引1的位置存儲(chǔ)第一個(gè)Cell對(duì)象

3.2.創(chuàng)建桶位Cell對(duì)象

                if ((as = cells) != null && (n = as.length) > 0) {    
              if ((a = as[(n - 1) & h]) == null) {
                    if (cellsBusy == 0) {     
                        Cell r = new Cell(x);  
                        if (cellsBusy == 0 && casCellsBusy()) {
                            boolean created = false;
                            try {             
                                Cell[] rs; int m, j;
                                if ((rs = cells) != null &&
                                    (m = rs.length) > 0 &&
                                    rs[j = (m - 1) & h] == null) {
                                    rs[j] = r;
                                    created = true;
                                }
                            } finally {
                                cellsBusy = 0;
                            }
                            if (created)
                                break;
                            continue;          
                        }
                    }

m - 1) & h 通過路由尋址公式找到對(duì)應(yīng)的索引位置的桶位為空,然后把創(chuàng)建的Cell對(duì)象存儲(chǔ)進(jìn)去

更直白就是說(shuō),你要蹲坑了,你要去找坑,如果坑位沒有人,你就進(jìn)去

3.3.擴(kuò)容Cell數(shù)組

 else if (cellsBusy == 0 && casCellsBusy()) {
                    try {
                        if (cells == as) {     
                            Cell[] rs = new Cell[n << 1];
                            for (int i = 0; i < n; ++i)
                                rs[i] = as[i];
                            cells = rs;
                        }
                    } finally {
                        cellsBusy = 0;
                    }
                    collide = false;
                    continue;                 
                }

數(shù)組長(zhǎng)度不夠時(shí),2倍擴(kuò)容

4.總結(jié)

你現(xiàn)在肯定是云里霧里,講的都是什么東西.

你現(xiàn)在就只需要知道 LongAdder

通過 base 和 Cell數(shù)組 換取更高的性能

5.附上源碼解析

當(dāng)然這里你可以跳過了,不用看了

5.1.add方法

public void add(long x) {
        // as 表示cells引用
        // b 表示獲取的base值
        // v 表示期望值
        // m 表示cells數(shù)組的長(zhǎng)度
        // a 表示當(dāng)前線程命中cell單元格
        Cell[] as; long b, v; int m; Cell a;
        //條件一: --> true 表示cells已經(jīng)初始化過了,當(dāng)前線程應(yīng)該把數(shù)據(jù)寫到對(duì)應(yīng)的cell中
        //        --> false 表示cells還沒有初始化過,當(dāng)前線程所有的數(shù)據(jù)都被寫到base中
        //條件二: --> false 表示cas替換值成功
        //        --> true 表示發(fā)生競(jìng)爭(zhēng)了,可能需要重試 或者 擴(kuò)容
        if ((as = cells) != null || !casBase(b = base, b + x)) {
            //什么時(shí)候會(huì)進(jìn)來(lái)?
            //1.true 表示cells已經(jīng)初始化過了,當(dāng)前線程應(yīng)該把數(shù)據(jù)寫到對(duì)應(yīng)的cell中
            //2.true cells還沒有初始化,但是發(fā)生競(jìng)爭(zhēng)了
            // true -> 未競(jìng)爭(zhēng)  false ->發(fā)生競(jìng)爭(zhēng)
            boolean uncontended = true;
            //as == null || (m = as.length - 1) < 0 看做是一個(gè)條件
            //條件一:true --> 說(shuō)明cells還沒有被初始化,也就是多線程寫base發(fā)生競(jìng)爭(zhēng)了進(jìn)來(lái)的,也就是通過第二個(gè)條件進(jìn)來(lái)的
            //      false --> 說(shuō)明cells已經(jīng)初始化了,可以去尋找自己的cell進(jìn)行賦值
            //條件二: getProbe() 可以理解為獲取當(dāng)前線程的hash值, m表示cells長(zhǎng)度-1  注意:cells的次方數(shù)一定是2的次方
            // true --> 說(shuō)明當(dāng)前線程對(duì)應(yīng)的下標(biāo)的cell為空,需要?jiǎng)?chuàng)建 longAccumulate 支持
            // false --> 說(shuō)明當(dāng)前線程對(duì)應(yīng)的下標(biāo)cell不為空,下一步需要將 x,添加到cell中
            //條件三: true --> 代表cas失敗,代表當(dāng)前線程對(duì)應(yīng)的cell,有競(jìng)爭(zhēng)
            //        false --> 表示cas成功
            if (as == null || (m = as.length - 1) < 0 ||
                (a = as[getProbe() & m]) == null ||
                !(uncontended = a.cas(v = a.value, v + x)))
                //都哪些情況會(huì)調(diào)用這里的方法?
                //1.true --> 說(shuō)明cells還沒有被初始化,也就是多線程寫base發(fā)生競(jìng)爭(zhēng)了進(jìn)來(lái)的
                //2.true --> 說(shuō)明當(dāng)前線程對(duì)應(yīng)的下標(biāo)的cell為空,需要?jiǎng)?chuàng)建 longAccumulate 支持
                //3.true --> 代表cas失敗,代表當(dāng)前線程對(duì)應(yīng)的cell,有競(jìng)爭(zhēng)
                longAccumulate(x, null, uncontended);
        }
    }

5.2.longAccumulate方法

 /**
     * //1.true --> 說(shuō)明cells還沒有被初始化,也就是多線程寫base發(fā)生競(jìng)爭(zhēng)了進(jìn)來(lái)的,到時(shí)候會(huì)進(jìn)行初始化cell
     * //2.true --> 說(shuō)明當(dāng)前線程對(duì)應(yīng)的下標(biāo)的cell為空,需要?jiǎng)?chuàng)建 longAccumulate 支持
     * //3.true --> 對(duì)應(yīng)的下標(biāo)也有cell,但是cas失敗,代表當(dāng)前線程對(duì)應(yīng)的cell,有競(jìng)爭(zhēng)
     */
    //wasUncontended,只有cells初始化之后,并且當(dāng)前線程 競(jìng)爭(zhēng)修改失敗,才會(huì)是false,其他情況下都是true
    final void longAccumulate(long x, LongBinaryOperator fn,
                              boolean wasUncontended) {
        //表示線程的hash值
        int h;
        //條件成立,說(shuō)明當(dāng)前線程還未分配hash值
        if ((h = getProbe()) == 0) {
            //給當(dāng)前線程分配hash值
            ThreadLocalRandom.current(); // force initialization
            //取出當(dāng)前線程的hash值賦值給h
            h = getProbe();
            //為什么?默認(rèn)情況下,可定寫入到了cell[0]的位置,不把他當(dāng)做一次真正的競(jìng)爭(zhēng)??
            wasUncontended = true;
        }
        //表示擴(kuò)容意向, false表示不會(huì)擴(kuò)容 , true有可能會(huì)擴(kuò)容
        boolean collide = false;                // True if last slot nonempty
        //自旋
        for (;;) {
            //as 表示cells引用
            //a 表示當(dāng)前線程命中的cell
            //n 表示cell的數(shù)組長(zhǎng)度
            //v 表示期望值
            Cell[] as; Cell a; int n; long v;
            //情況1:as不為空表示cells已經(jīng)初始化了,當(dāng)前線程應(yīng)該將數(shù)據(jù)寫入到對(duì)應(yīng)的cell中
            if ((as = cells) != null && (n = as.length) > 0) {
                //2.true --> 說(shuō)明當(dāng)前線程對(duì)應(yīng)的下標(biāo)的cell為空,需要?jiǎng)?chuàng)建 longAccumulate 支持
                //3.true --> 代表cas失敗,代表當(dāng)前線程對(duì)應(yīng)的cell,有競(jìng)爭(zhēng)[重試或者擴(kuò)容]
                //情況1.1: true 表示當(dāng)前線程對(duì)應(yīng)的下標(biāo)位置的cell為null,需要?jiǎng)?chuàng)建cell
                if ((a = as[(n - 1) & h]) == null) {
                    //true 表示當(dāng)前鎖未被占用,false-->表示鎖被占用
                    if (cellsBusy == 0) {       // Try to attach new Cell
                        //拿x創(chuàng)建cell
                        Cell r = new Cell(x);   // Optimistically create
                        //條件一:true 表示當(dāng)前鎖未被占用,false-->表示鎖被占用
                        //條件二:true表示當(dāng)前線程獲取鎖成功,false表示當(dāng)前線程獲取鎖失敗,
                        if (cellsBusy == 0 && casCellsBusy()) {
                            //是否創(chuàng)建成功的標(biāo)記
                            boolean created = false;
                            try {               // Recheck under lock
                                //rs表示cells引用
                                //m 表示cells長(zhǎng)度
                                //j 表示當(dāng)前線程命中的下標(biāo)
                                Cell[] rs; int m, j;
                                //條件一,條件二,恒成立的
                                //rs[j = (m - 1) & h] == null 為了防止其他線程已經(jīng)初始化話過了,防止當(dāng)前線程再次修改,覆蓋掉原來(lái)的cell
                                if ((rs = cells) != null &&
                                    (m = rs.length) > 0 &&
                                    rs[j = (m - 1) & h] == null) {
                                    rs[j] = r;
                                    created = true;
                                }
                            } finally {
                                cellsBusy = 0;
                            }
                            if (created)
                                break;
                            continue;           // Slot is now non-empty
                        }
                    }
                    //擴(kuò)容意向改為false
                    collide = false;
                }
                //情況1.2
                //wasUncontended,只有cells初始化之后,并且當(dāng)前線程 競(jìng)爭(zhēng)修改失敗,才會(huì)是false,其他情況下都是true
                else if (!wasUncontended)       // CAS already known to fail
                    wasUncontended = true;      // Continue after rehash
                //情況1.3 :當(dāng)前線程rehash過后,然后新命中的cell不為空
                //true --> 寫成功 退出
                //false -- > rehash過后命中的cell,也有競(jìng)爭(zhēng)  這里為重試一次,再重試一次
                else if (a.cas(v = a.value, ((fn == null) ? v + x :
                                             fn.applyAsLong(v, x))))
                    break;
                    //情況1.4.
                    // 條件一: n >= NCPU  true --> 擴(kuò)容意向改為False ,表示不擴(kuò)容了   false --> 表示cells還可以擴(kuò)容
                   //條件二:  true --> 表示其他線程已經(jīng)擴(kuò)容過了,當(dāng)前線程rehash之后重試即可
                else if (n >= NCPU || cells != as)
                    collide = false;            // At max size or stale
                //默認(rèn)開始為false 的, 設(shè)置為true,需要擴(kuò)容,但是不一定真的發(fā)生擴(kuò)容
                else if (!collide)
                    collide = true;
                //情況6.真正的擴(kuò)容邏輯
                //條件一: cellsBusy == 0 true  --> 表示當(dāng)前無(wú)鎖狀態(tài),當(dāng)前線程可以去競(jìng)爭(zhēng)這把鎖
                //條件二:casCellsBusy() true --> 表示當(dāng)前線程獲取鎖成功,可以執(zhí)行擴(kuò)容邏輯 ,false 表示有其他線程在做相關(guān)的操作
                // 嘗試兩次之后
                else if (cellsBusy == 0 && casCellsBusy()) {
                    try {
                        if (cells == as) {      // Expand table unless stale
                            //n<<1 翻倍
                            Cell[] rs = new Cell[n << 1];
                            for (int i = 0; i < n; ++i)
                                rs[i] = as[i];
                            cells = rs;
                        }
                    } finally {
                        //釋放鎖
                        cellsBusy = 0;
                    }
                    collide = false;
                    continue;                   // Retry with expanded table
                }
                //重置當(dāng)前線程hash值
                h = advanceProbe(h);
            }
            //情況2:前置條件,cells為進(jìn)行初始化,as為null
            //條件一: cellsBusy為true當(dāng)前未加鎖
            //條件二: cells == as 為什么? 因?yàn)槠渌€程在你給as賦值之后修改了cells
            //條件三: true 表示獲取鎖成功 ,會(huì)把cellBusy 設(shè)置為 1 , false 表示其他線程在持有這個(gè)鎖
            else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
                boolean init = false;
                try {
                    // 為什么還有一次判斷呢?
                    //防止其他線程已經(jīng)初始化了,當(dāng)前線程再次初始化,導(dǎo)致丟失數(shù)據(jù)
                    if (cells == as) {
                        Cell[] rs = new Cell[2];
                        rs[h & 1] = new Cell(x);
                        cells = rs;
                        init = true;
                    }
                } finally {
                    //釋放鎖
                    cellsBusy = 0;
                }
                if (init)
                    break;
            }
            //情況三:
            //1.當(dāng)前cellBusy加鎖狀態(tài),表示其他線程正在初始化cells,所以當(dāng)前線程累加到base
            //2.cells被其他線程初始化之后,當(dāng)前線程需要將數(shù)據(jù)累加到base
            else if (casBase(v = base, ((fn == null) ? v + x :
                                        fn.applyAsLong(v, x))))
                break;                          // Fall back on using base
        }
    }

以上就是LongAdder原理及創(chuàng)建使用示例詳解的詳細(xì)內(nèi)容,更多關(guān)于LongAdder創(chuàng)建使用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java合并兩個(gè)相同的List集合的四種方法解析

    Java合并兩個(gè)相同的List集合的四種方法解析

    這篇文章主要給大家介紹了關(guān)于Java合并兩個(gè)相同的List集合的四種方法,在Java編程中常需合并兩個(gè)List,常用addAll()方法,簡(jiǎn)單高效,Java8起可用Stream的concat()方法,并發(fā)場(chǎng)景下,CopyOnWriteArrayList類保證線程安全,Collections.union()合并且去重,需要的朋友可以參考下
    2024-10-10
  • java讀取配置文件(properties)的時(shí)候,unicode碼轉(zhuǎn)utf-8方式

    java讀取配置文件(properties)的時(shí)候,unicode碼轉(zhuǎn)utf-8方式

    這篇文章主要介紹了java讀取配置文件(properties)的時(shí)候,unicode碼轉(zhuǎn)utf-8方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • java后端如何實(shí)現(xiàn)防止接口重復(fù)提交

    java后端如何實(shí)現(xiàn)防止接口重復(fù)提交

    這篇文章主要介紹了java后端如何實(shí)現(xiàn)防止接口重復(fù)提交問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Spring?Boot中使用Spring?MVC的示例解析

    Spring?Boot中使用Spring?MVC的示例解析

    MVC?是一種常見的軟件設(shè)計(jì)模式,用于分離應(yīng)用程序的不同部分以實(shí)現(xiàn)松散耦合和高內(nèi)聚性,這篇文章主要介紹了如何在Spring?Boot中使用Spring?MVC,需要的朋友可以參考下
    2023-04-04
  • mybatis時(shí)間范圍查詢代碼示例

    mybatis時(shí)間范圍查詢代碼示例

    這篇文章主要給大家介紹了關(guān)于mybatis時(shí)間范圍查詢的相關(guān)資料,在項(xiàng)?中避免不了要?到時(shí)間范圍查詢,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • java高級(jí)用法之JNA中使用類型映射

    java高級(jí)用法之JNA中使用類型映射

    JNA中有很多種映射,本文主要介紹了java高級(jí)用法之JNA中使用類型映射,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-03-03
  • 淺談spring ioc的注入方式及注入不同的數(shù)據(jù)類型

    淺談spring ioc的注入方式及注入不同的數(shù)據(jù)類型

    這篇文章主要介紹了淺談spring ioc的注入方式及注入不同的數(shù)據(jù)類型,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • Spring Security Oauth2.0 實(shí)現(xiàn)短信驗(yàn)證碼登錄示例

    Spring Security Oauth2.0 實(shí)現(xiàn)短信驗(yàn)證碼登錄示例

    本篇文章主要介紹了Spring Security Oauth2.0 實(shí)現(xiàn)短信驗(yàn)證碼登錄示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • JAVA防止重復(fù)提交Web表單的方法

    JAVA防止重復(fù)提交Web表單的方法

    這篇文章主要介紹了JAVA防止重復(fù)提交Web表單的方法,涉及Java針對(duì)表單的相關(guān)處理技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • RabbitMQ 的消息持久化與 Spring AMQP 的實(shí)現(xiàn)詳解

    RabbitMQ 的消息持久化與 Spring AMQP 的實(shí)現(xiàn)詳解

    這篇文章主要介紹了RabbitMQ 的消息持久化與 Spring AMQP 的實(shí)現(xiàn)剖析詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08

最新評(píng)論

囊谦县| 津市市| 宁晋县| 甘肃省| 宿州市| 荣成市| 华阴市| 肃北| 桂阳县| 太仆寺旗| 当涂县| 新沂市| 永清县| 泸西县| 临沭县| 靖宇县| 易门县| 林甸县| 涞源县| 合川市| 公主岭市| 石林| 郓城县| 昌邑市| 卓尼县| 荆门市| 伊吾县| 赣州市| 绥阳县| 洪洞县| 长沙县| 高台县| 四子王旗| 郁南县| 江北区| 荣昌县| 徐水县| 兰溪市| 吉首市| 当雄县| 买车|