介绍
Java不同并发场景下LongAdder和AtomicLong如何使用以及Atomic的核心原理CAS(Compare-And-Swap)机制
1.什么是原子操作?
原子操作是指操作在执行过程中不可被中断,要么全部执行成功,要么全部失败。
2.为什么需要 Atomic 类?
传统方式的局限性:
使用synchronized或ReentrantLock确保线程安全,但代价是性能的下降。
Atomic类的优势:
通过CAS实现非阻塞操作,性能更高。
3.高并发下LongAdder比AtomicLong效率高,本质是空间换时间
LongAdder是JDK8新增的类。
高并发下LongAdder比AtomicLong效率高,其本质是空间换时间。 在竞争激烈的时候,LongAdder把不同线程对应到不同的Cell上进行修改,降低了冲突的概率,是多段锁的理念,提高了并发性。
AtomicLong中有个内部变量value保存着实际的long值,所有的操作都是针对该变量进行。也就是说,高并发环境下,value变量其实是一个热点,也就是N个线程竞争一个热点。由于竞争很激烈,每一次操作,都要flush和refresh,导致很多资源浪费。
LongAdder的基本思路就是分散热点,将value值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。如果要获取真正的long值,只要将各个槽中的变量值累加返回。但在统计的时候,如果有并发更新,可能会导致统计的数据有些误差。
4.线程竞争很低或需要准确的数值,使用AtomicLong
在线程竞争很低的情况下进行计数,使用AtomicLong还是更简单,更直接一些,并且效率会稍微高一点点。
其他的情况下,比如序列号生成啦,这种情况下需要准确的数值。 全局唯一的AtomicLong才是正确的选择
。
5.Atomic的核心原理CAS(compareAndSwap)
public final int getAndAddInt(Object var1, Long var2, int var4){
int var5;
do{
var5 = this.getIntVolatile(var1, var2);
}while(!this.compareAndSwapInt(var1, var2, var5,var5 + var4));
return var5;
}
/**
* var1 传入的对象(count对象)
* var2 加数
* var5 底层的加数
* var5 + var4 底层的加数 + 增加量
*/
对于当前var1(count)对象,如果当前值var2,与底层值var5相同,那么把它更新成后面的值。 因为当执行更新操作时,可能会被其他线程修改,所以需要判断。