LongAdder原理

LongAdder是为了解决高并发下Atomic类频繁CAS操作导致的CPU资源浪费问题,它通过牺牲空间来换取时间效率。在多个线程对同一个变量加1时,LongAdder将更新压力分散到一个Cell数组,降低并发冲突。源码中,add方法将并发修改分散到Cell数组,sum方法则计算所有Cell和value的总和。
摘要由CSDN通过智能技术生成

对于longAdder的应用,也是在看到concurrentHashMap源码中,统计数组中元素个数的时候,看到了Doug Lea写的一个注释,才开始去关注这个类,这里主要记录下自己对该类源码的学习笔记
在这里插入图片描述

longAdder核心思想

通常,在说到这个类的时候,会和atomic中原子类有关系,atomicInteger底层的话,通过unsafe中的native方法进行compareAndSwap方法去进行值的更新,同时,在atomic类中声明的value是volatile修饰,保证了可见性;这个是没问题的,但是有一个问题:如果有多个线程来对一个值进行修改的时候,同一时刻,只会有一个线程去更新成功,其他的线程会不停的cas自旋,这样的话,会消耗CPU的资源;此时:LongAdder就可以出场了,简单而言,longAdder是以空间换时间

在这里插入图片描述
对于atomicLong来说,只有前一个value,如果多个线程对一个字段进行加1,其他线程会不停得自旋,直到当前线程对该值+1成功;
那LongAdder怎么做的呢?在多个线程对同一个变量进行+1的时候,会把对value的压力,分散到一个cell数组中,也就是图中后面的value1、value2…valueN,这样的话,虽然需要额外再维护一个数组,但是可以提高并发量,也就是所谓的以空间换时间

源码

在这里插入图片描述
这是longAdder的继承关系

我们来看对应的add方法

add()
/**
 * Adds the given value.
 *
 * cells是volatile修饰的cell数组
 * base:也是volatile修饰的变量,在尝试+1 的时候,其实就是对base变量进行+1
 * 如果base变量+1失败,就需要将+1的操作,转移到cell数组中的某个节点对应的value
 * 在获取总数的时候,就是 base + cell[0] + cell[1] + ... + cell[n]
 *
 * @param x the value to add
 */
public void add(long x) {
   
	Cell[] as; long b, v; int m; Cell a;
	/**
	 * 如果cas设置base的值成功,那就无需进入,直接结束运行
	 * 如果cas设置失败,有可能是并发请求导致失败,就会将该线程需要 + 1的动作,放到cell中执行
	 */
	if ((as = cells) != null || !casBase(b = base, b + x)) {
   
		boolean uncontended = true;
		/**
		 * 下面这个if判断,最为重要的是最后一个cas
		 * 如果代码执行到最后一个cas表示,当前cells[i]位置不为null,直接cas设置cells[i]位置的值 +1
		 * 如果成功,结束运行
		 * 否则就进入longAccumulate
		 *
		 * getProbe()是根据当前线程生成的一个值,其实是为了判断当前线程 + 1的动作,需要放在数组中的哪个位置执行
		 */
		if (as == null || (m = as.length - 1) < 0 ||
			(a = as[getProbe() & m]) == null ||
			!(uncontended = a.cas(v = a.value, v + x)))
			longAccumulate
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值