溫馨提示×

溫馨提示×

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

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

Java并發(fā)編程之LongAdder源碼分析

發(fā)布時間:2023-04-27 15:16:00 來源:億速云 閱讀:188 作者:iii 欄目:開發(fā)技術(shù)

這篇“Java并發(fā)編程之LongAdder源碼分析”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Java并發(fā)編程之LongAdder源碼分析”文章吧。

前言

根據(jù)源碼來分析一下它的基本實現(xiàn)流程。

This class is usually preferable to AtomicLong when multiple threads update a common sum that is used for purposes such as collecting statistics, not for fine-grained synchronization control. Under low update contention, the two classes have similar characteristics. But under high contention, expected throughput of this class is significantly higher, at the expense of higher space consumption.

上面這段話是LongAdder源碼注釋中的一部分,翻譯過來意思大概是

當(dāng)多個線程更新用于收集統(tǒng)計信息但不用于細(xì)粒度同步控制的目的的公共和時,此類通常優(yōu)于AtomicLong。 在低更新爭用下,這兩個類具有相似的特征。 但在高爭用的情況下,這一類的預(yù)期吞吐量明顯更高,但代價是空間消耗更高。

也就是說LongAdder在并發(fā)度高的情況下效率更高,但是代價是以空間換時間。

通俗地解釋一下LongAdder的原理:當(dāng)并發(fā)少的時候,累加操作只在一個變量base上執(zhí)行就夠用了,所以和AtomicLong類似;但是當(dāng)并發(fā)量上來的時候,如果還是在變量base上進(jìn)行操作就會有很多線程阻塞,所以就創(chuàng)建一個數(shù)組cells,在數(shù)組的每一個元素上都可以進(jìn)行累加,最后計算結(jié)果時再就算一下basecells數(shù)組每個元素的和就行了。而線程具體在數(shù)組的哪一位進(jìn)行操作可以通過計算hash來確定索引位置。

源碼簡介

LongAdder從父類Striped64繼承過來的屬性,這里的Cell是一個用來進(jìn)行累加操作的內(nèi)部類,內(nèi)部有一個value屬性來存儲累加的值。

// CPU核心數(shù)
static final int NCPU = Runtime.getRuntime().availableProcessors();
// 并發(fā)高時進(jìn)行累加的Cell數(shù)組
transient volatile Cell[] cells;
// 多個線程沒有競爭時在base上進(jìn)行累加
transient volatile long base;
// Cell數(shù)組是否正在創(chuàng)建或擴(kuò)容
transient volatile int cellsBusy;

累加操作方法increment()實際調(diào)用的是add(1L),所以我們直接來看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);
    }
}

首先來看第一個if語句,初始狀況下cellsnull,所以會進(jìn)行casBase操作,也就是在base變量上進(jìn)行累加,如果操作成功了說明當(dāng)前沒有競爭,所以就結(jié)束了。

當(dāng)并發(fā)量上來的時候,進(jìn)行casBase方法就有可能會失敗,所以這時進(jìn)入第二個if語句判斷。

  • 第一次進(jìn)來時Cell數(shù)組asnull,所以就會執(zhí)行longAccumulate,對Cell數(shù)組as進(jìn)行初始化并且在索引1位置累加1

  • 之后再執(zhí)行到這個if語句as就不是null了,而且數(shù)組長度也大于0

  • a = as[getProbe() & m]) == null,這句話簡單的理解就是在數(shù)組as中隨機(jī)找到一個索引位置,判斷該位置的值是不是null,如果是null的話就執(zhí)行longAccumulate,不是null繼續(xù)向下判斷

  • !(uncontended = a.cas(v = a.value, v + x))這句話的意思是,在找到的這個索引位置進(jìn)行累加操作,如果成功了就結(jié)束操作,如果失敗了就執(zhí)行longAccumulate

以上就是關(guān)于“Java并發(fā)編程之LongAdder源碼分析”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI