AtomicLong 与 LongAdder(CAS机制的优化)

线程安全性-原子性-CAS
LongAdder是java8为我们提供的新的类,跟AtomicLong有相同的效果。是对CAS机制的优化。

AtomicLong:
//变量声明
public static AtomicLong count = new AtomicLong(0);
//变量操作
count.incrementAndGet();
//变量取值
count.get();
LongAdder:
//变量声明
public static LongAdder count = new LongAdder();
//变量操作
count.increment();
//变量取值
count

为什么有了AtomicLong还要新增一个LongAdder呢?
原因是:CAS底层实现是在一个死循环中不断地尝试修改目标值,直到修改成功。如果竞争不激烈的时候,修改成功率很高,否则失败率很高。在失败的时候,这些重复的原子性操作会耗费性能。(不停的自旋,进入一个无限重复的循环中)

知识点: 对于普通类型的long、double变量,JVM允许将64位的读操作或写操作拆成两个32位的操作。

核心思想:将热点数据分离。
比如说它可以将AtomicLong内部的内部核心数据value分离成一个数组,每个线程访问时,通过hash等算法映射到其中一个数字进行计数,而最终的计数结果则为这个数组的求和累加,其中热点数据value会被分离成多个单元的cell,每个cell独自维护内部的值。当前对象的实际值由所有的cell累计合成,这样热点就进行了有效地分离,并提高了并行度。这相当于将AtomicLong的单点的更新压力分担到各个节点上。在低并发的时候通过对base的直接更新,可以保障和AtomicLong的性能基本一致。而在高并发的时候通过分散提高了性能。

源码:
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);
    }
}

缺点:如果在统计的时候,如果有并发更新,可能会有统计数据有误差。
实际使用中在处理高并发计数的时候优先使用LongAdder,而不是AtomicLong在线程竞争不激烈的时候,使用AtomicLong会简单效率更高一些。比如序列号生成(准确性)


大白话聊聊Java并发面试问题之Java 8如何优化CAS性能?
LongAdder
在LongAdder的底层实现中,首先有一个base值,刚开始多线程来不停的累加数值,都是对base进行累加的,比如刚开始累加成了base = 5。

并发更新的线程数量过多时,施行分段CAS的机制(Cell数组,每个数组是一个数值分段)

这时,让大量的线程分别去对不同Cell内部的value值进行CAS累加操作,这样就把CAS计算压力分散到了不同的Cell分段数值中了!

这样就可以大幅度的降低多线程并发更新同一个数值时出现的无限循环的问题,大幅度提升了多线程并发更新数值的性能和效率!

而且他内部实现了自动分段迁移的机制,也就是如果某个Cell的value执行CAS失败了,那么就会自动去找另外一个Cell分段内的value值进行CAS操作。

这样也解决了线程空旋转、自旋不停等待执行CAS操作的问题,让一个线程过来执行CAS时可以尽快的完成这个操作。

最后,如果你要从LongAdder中获取当前累加的总值,就会把base值和所有Cell分段数值加起来返回给你。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AtomicLong是一个Java原子类,用于对长整型数据进行原子操作。它提供了一系列方法,可以实现原子性的增加、减少、设置、获取等操作。与AtomicInteger类似,AtomicLong的使用方式也类似。 AtomicLong是线程安全的,它使用了CAS(Compare and Swap)机制来保证操作的原子性。CAS是一种乐观锁的实现方式,它通过比较内存中的值与期望值来确定是否修改,如果相等则修改,否则重新尝试。这种方式可以避免使用锁,提高了并发性能。 在编译成字节码时,编译器会判断当前JVM或机器硬件是否支持8字节的CAS操作。如果支持,则使用无锁的方式实现原子操作;如果不支持,则会使用加锁处理。这样可以保证在不同的环境下都能正常使用AtomicLong。 总结来说,AtomicLong是一个用于对长整型数据进行原子操作的Java类,它提供了一系列方法,使用CAS机制来保证操作的原子性。它的使用方式与AtomicInteger类似,并且在编译器会根据环境选择合适的实现方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java concurrency之AtomicLong原子类_动力节点Java学院整理](https://download.csdn.net/download/weixin_38747818/12778861)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [并发编程 — 原子AtomicLong 详解](https://blog.csdn.net/small_love/article/details/111057686)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值