CAS自旋锁解析——JUC多线程与高并发系列笔记

1、比较与交换

a、拷贝主内存中变量的值到工作内存中
b、CAS修改原始值
c、比较要修改的值与主内存中的值是否相等
d、不相等则自旋获取最新的值,然后从a操作开始重新执行

2、自旋锁与unsafe

CAS底层其实是使用unsafe类来实现的,unSafe是JDK下rt.jar文件sun.misc包下的类,类中都是native方法,是调用jvm的本地方法,其方法可以直接像C语言的指针一样操作内

unSafe可以通过内存地址偏移量来获取数据

在unSafe中的value使用了volatile修饰符,以此实现多线程的可见性

unSafe是通过硬件的功能来实现原子性,CAS是一种原语,它是通过几条指令组成的,用于完成某项功能,并且原语的执行必须是连续的,在执行过程中不能被打断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。实例:getAndIncrement方法

1、获取当前对象主内存中的值,拷贝到工作内存中
2、然后通过while循环去拿到工作内存中的值和主内存中的值进行比较
3、如果相同则修改成功
4、否则继续从第一步开始

CAS的优点在于它是没有在代码上加锁的一种自旋锁机制,通过自旋判断原始值和拷贝值是否相等的方式,可以让多个线程同时执行一段代码,而不是进行阻塞,因此可以提高多线程执行的吞吐量。

当然此时可能会存在一个比较诡异的问题,它就是ABA问题,下面我们会讲解

UnSafe的compareAndSwapInt方法的底层实现展示:

补充一个小知识点:getAndIncrement和incrementAndGet的区别

由于getAndIncrement方法在源码中,是通过unsafe调用getAndAddInt() 方法,在getAndAddInt方法中,它返回的是this的原值,因此直接返回这个值是并没有加1的,但是this的值是在compareAndSwapInt方法中加了1,所以直接获取当前对象的值是自增了。


而incrementAndGet方法看源码就很清楚了

它直接在通过unsafe调用getAndInt方法后加1,这样返回的值就是加了1。可以实现赋值的变量拿到自增的值。

具体可以看一下代码实现:

3、CAS的缺点:

1、由于CAS是通过自旋锁实现,通过do while不断的循环来达到数据一致性,因此在并发量超大的一个情况下,如果长时间不能修改成功,大量请求同时自旋会造成CPU性能占用大,可能导致系统宕机。

2、只能保证一个共享变量的原子问题

3、ABA问题:当共享变量被修改后,又被修改回原值的情况,就是ABA问题,例如1->2->1解决方式:

1、通过AtomicReference原子引用来处理,在类的泛型下通过包装对象来加入变量和一个版本号属性来解决,如果变量被改变则版本号也修改时间戳,如果版本号不相同则证明被修改过。

2、JDK提供了带版本号stamp的原子引用类AtomicStampedReference,它提供版本更新的功能。

测试代码:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值