Java并发面试问题之Java 8如何优化CAS性能

java并发包下的CAS相关的原子操作,以及Java 8如何改进和优化CAS操作的性能。
因为Atomic系列的原子类,无论在并发编程、JDK源码、还是各种开源项目中,都经常用到。而且在Java并发面试中,这一块也属于比较高频的考点,所以还是值得给大家聊一聊。

问题:假设多个线程需要对一个变量不停的累加1,怎么办,有什么问题?
《并发问题》

1.初步解决方案:synchronized
让他通过加锁的方式变成线程安全的:

private int data = 0 ;
public synchronized void increment(){
	data++;
}

会出现的问题:如此简单的data++操作,都要加一个重磅的synchronized锁来解决多线程并发问题,就有点杀鸡用牛刀,大材小用了。

2.更高效的解决方案:Atomic原子类及其底层原理
我们完全可以换一种解决方案:java并发包下面提供了一系列的Atomic原子类,比如说AtomicInteger。
他可以保证多线程并发安全的情况下,高性能的并发更新一个数值:

    private AtomicInteger data = new AtomicInteger();
	data.incrementAndGet()

这个代码中,大家就见不到加锁、解锁的操作了吧。
实际上,Atomic原子类底层使用的不是传统意义上的锁机制,而是无锁化的CAS机制,通过CAS机制保证多线程修改一个数值的原子性。

3.那什么是CAS呢?
全名:Compare and Set
含义:顾名思义,就是先比较,再进行赋值的操作
简单的操作示意图如下:
在这里插入图片描述
4.Java8对CAS机制的优化
3中所说的CAS机制是否存在问题呢?那必然存在。
问题:比如说大量的线程同时并发修改一个AtomicInterger值,可能会导致很多线程不停的自旋,进入一个无限循环的状态。
在大量线程高并发更新AtomicInteger的时候,这种问题可能会比较明显,导致大量线程空循环,自旋转,性能和效率都不是特别好

于是,JAVA8推出了一个类,LongAdder!他就是尝试使用分段CAS以及自动分段迁移的方式来大幅度提升多线程高并发执行CAS操作的性能!

在这里插入图片描述
实现原理:
在LongAdder的底层实现中,首先有一个base值,刚开始多线程来不停的累加数值,都是对base进行累加的,比如刚开始累加成了base = 5。
接着如果发现并发更新的线程数量过多,就会开始施行分段CAS的机制,也就是内部会搞一个Cell数组,每个数组是一个数值分段。
这时,让大量的线程分别去对不同Cell内部的value值进行CAS累加操作,这样就把CAS计算压力分散到了不同的Cell分段数值中了!
这样就可以大幅度的降低多线程并发更新同一个数值时出现的无限循环的问题,大幅度提升了多线程并发更新数值的性能和效率!
而且他内部实现了自动分段迁移的机制,也就是如果某个Cell的value执行CAS失败了,那么就会自动去找另外一个Cell分段内的value值进行CAS操作。
这样也解决了线程空旋转、自旋不停等待执行CAS操作的问题,让一个线程过来执行CAS时可以尽快的完成这个操作。
最后,如果你要从LongAdder中获取当前累加的总值,就会把base值和所有Cell分段数值加起来返回给你。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值