成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Java并發(fā)】淺析 AtomicLong & LongAdder

zhjx922 / 3038人閱讀

摘要:最終依舊使用來更新值。此時(shí)使用能更好地提升性能。適用于高并發(fā)情況下的計(jì)數(shù)操作,利用與相似的原理,以空間換時(shí)間,提高了實(shí)際的計(jì)數(shù)效率。

AtomicLong
/**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
public final long incrementAndGet() {
    return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
}
unsafe
public final long getAndAddLong(Object var1, long var2, long var4) {
    long var6;
    do {
        var6 = this.getLongVolatile(var1, var2);
    } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
    // 關(guān)注重點(diǎn):if(var2 == var6)
    return var6;
}

var1 調(diào)用原方法 incrementAndGet 即自身的對象

var2 原對象當(dāng)前(工作內(nèi)存中的)值

var4 要加上去的值

var6 調(diào)用底層方法 getLongVolatile 獲得當(dāng)前(主內(nèi)存中的)值,如果沒其他線程修改即與 var2 相等

compareAndSwapLong

var2var6 為什么可能會不一樣?

在并發(fā)環(huán)境下,工作內(nèi)存中的值 var2 與主內(nèi)存中的值 var6 之間的可能不一樣(JMM)

// 獲取主內(nèi)存里的值
public native long getLongVolatile(Object var1, long var2);
// CAS 操作
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
native關(guān)鍵字說明其修飾的方法是一個(gè)原生態(tài)方法,方法對應(yīng)的實(shí)現(xiàn)不是在當(dāng)前文件,而是在用其他語言(如 C 和 C++)實(shí)現(xiàn)的文件中。Java 語言本身不能對操作系統(tǒng)底層進(jìn)行訪問和操作,但是可以通過JNI接口調(diào)用其他語言來實(shí)現(xiàn)對底層的訪問。
LongAdder
public void increment() {
    add(1L);
}

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); // <- 重點(diǎn)
    }
}
Cell

Cell 類,是一個(gè)普通的二元算術(shù)累積單元,它在 Striped64 里面。Striped64 這個(gè)類使用分段的思想,來盡量平攤并發(fā)壓力(類似1.7及以前版本的 ConcurrentHashMap.Segment)。

最終依舊使用 compareAndSwapLong 來更新值。

/**
 * Padded variant of AtomicLong supporting only raw accesses plus CAS.
 *
 * JVM intrinsics note: It would be possible to use a release-only
 * form of CAS here, if it were provided.
 */
@sun.misc.Contended static final class Cell {
    volatile long value;
    Cell(long x) { value = x; }
    final boolean cas(long cmp, long val) {
        return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
    }

    // Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    private static final long valueOffset;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class ak = Cell.class;
            valueOffset = UNSAFE.objectFieldOffset
                (ak.getDeclaredField("value"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
}
longAccumulate

Long 映射到 Cell[] 數(shù)組里面,通過 Hash 等算法映射到其中一個(gè)數(shù)字進(jìn)行計(jì)數(shù),而最終的計(jì)數(shù)結(jié)果就是其求和累加。在低并發(fā)的時(shí)候,通過對 base 的直接更新,可以很好地保證和 Atomic 性能的基本一致;而在高并發(fā)的時(shí)候,則將單點(diǎn)的更新壓力分散到各個(gè)節(jié)點(diǎn)上,提升了性能。

總結(jié)

AtomicLong 適用于序號生成,這種情況下需要準(zhǔn)確的、全局唯一的數(shù)值;但在高并發(fā)情況下的計(jì)數(shù)操作,使用 AtomicLong 時(shí)會因線程競爭導(dǎo)致失敗白白循環(huán)一次;失敗次數(shù)越多,循環(huán)次數(shù)也越多。此時(shí)使用LongAdder 能更好地提升性能。

LongAdder 適用于高并發(fā)情況下的計(jì)數(shù)操作,利用與 JDK1.7 ConcurrentHashMap 相似的原理,以空間換時(shí)間,提高了實(shí)際的計(jì)數(shù)效率。當(dāng)然,線程競爭很低的情況下進(jìn)行計(jì)數(shù),使用 AtomicLong 還是更簡單更直接,并且效率稍微高一些。

注意:CAS 是 sun.misc.Unsafe 中提供的操作,只對 int、long、對象類型(引用或者指針)提供了這種操作,其他類型都需要轉(zhuǎn)化為這三種類型才能進(jìn)行 CAS 操作。(例如 DoubleAdder 就是 LongAdder 的簡單改造,主要的變化就是用 Double.longBitsToDoubleDouble.doubleToRawLongBits 對底層的8字節(jié)數(shù)據(jù)進(jìn)行 long <=> double 轉(zhuǎn)換,存儲的時(shí)候使用 long 型,計(jì)算的時(shí)候轉(zhuǎn)化為 double 型。)

參考資料

談?wù)凜oncurrentHashMap1.7和1.8的不同實(shí)現(xiàn)

jdk1.8 LongAdder源碼學(xué)習(xí)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/69085.html

相關(guān)文章

  • Java多線程進(jìn)階(十七)—— J.U.C之a(chǎn)tomic框架:LongAdder

    摘要:在并發(fā)量較低的環(huán)境下,線程沖突的概率比較小,自旋的次數(shù)不會很多。比如有三個(gè),每個(gè)線程對增加。的核心方法還是通過例子來看假設(shè)現(xiàn)在有一個(gè)對象,四個(gè)線程同時(shí)對進(jìn)行累加操作。 showImg(https://segmentfault.com/img/remote/1460000016012084); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... ...

    fengxiuping 評論0 收藏0
  • 還在用Synchronized?Atomic你了解不?

    摘要:失敗重試自旋比如說,我上面用了個(gè)線程,對值進(jìn)行加。我們都知道如果在線程安全的情況下,這個(gè)值最終的結(jié)果一定是為的。那就意味著每個(gè)線程都會對這個(gè)值實(shí)質(zhì)地進(jìn)行加。 前言 只有光頭才能變強(qiáng) 之前已經(jīng)寫過多線程相關(guān)的文章了,有興趣的同學(xué)可以去了解一下: https://github.com/ZhongFuCheng3y/3y/blob/master/src/thread.md showImg(h...

    陳江龍 評論0 收藏0
  • AtomicInteger 原子類的作用

    摘要:原子類的作用多線程操作,性能開銷太大并不是原子操作。每次比較的是兩個(gè)對象性能比要好使用時(shí),在高并發(fā)下大量線程會同時(shí)去競爭更新同一個(gè)原子變量,但是由于同時(shí)只有一個(gè)線程的會成功,所以其他線程會不斷嘗試自旋嘗試操作,這會浪費(fèi)不少的資源。 AtomicInteger 原子類的作用 多線程操作,Synchronized 性能開銷太大count++并不是原子操作。因?yàn)閏ount++需要經(jīng)過讀取-...

    MartinDai 評論0 收藏0
  • Java 8 并發(fā): 原子變量和 ConcurrentMap

    摘要:在有些情況下,原子操作可以在不使用關(guān)鍵字和鎖的情況下解決多線程安全問題。但其內(nèi)部的結(jié)果不是一個(gè)單一的值這個(gè)類的內(nèi)部維護(hù)了一組變量來減少多線程的爭用。當(dāng)來自多線程的更新比讀取更頻繁時(shí)這個(gè)類往往優(yōu)于其他的原子類。 原文地址: Java 8 Concurrency Tutorial: Atomic Variables and ConcurrentMap AtomicInteger java...

    yy13818512006 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<