CAS(compare and swap)

严格来说,和Java无关。包括jvm中关于cas的api,都放在unsafe包里。

一个特殊的cpu指令,完成的工作是“比较和交换”。

        比较address内存地址中的值,是否和expected寄存器中的值相同。如果相同,就把swap寄存器的值和address内存中的值进行交换,返回true。如果不相同,则无事发生,返回false。

一、原子类

基于cas指令,给编写线程安全的代码,打开了一个新世界的大门。

        之前线程安全都是靠加锁,加锁 => 阻塞 => 性能降低

        使用CAS不涉及加锁,不会阻塞,合理使用也可保证线程安全 => 无锁编程

CAS本身是cpu指令,操作系统对指令进行了封装,jvm又对操作系统提供的api封装了一层。

        Java中CAS的api放到了unsafe包中,这样的操作,涉及到一些系统底层的内容,使用不当的话可能会带来一些风险,不建议直接使用CAS

        Java的标准库,对于CAS进行了进一步封装,提供了一个工具类,以供使用。

最主要的工具,叫做“原子类” java.util.concurrent.atomic

         AtomicInteger,AtomicLong对Integer和Long进行了封装,针对这样的对象进行了多线程编程,就是线程安全的。

通过CAS的方式实现的。这里的内容不加锁,也能保证线程安全。并且这个代码更高效,不涉及阻塞等待。

count ++ 是三个指令,会相互穿插执行,引起线程不安全。

getAndIncrement 是对变量的修改,是CAS指令(原子的

二、实现自旋锁

原子的自增:

        这里其实oldValue期望是一个放到寄存器里的值,这个值就是初始化成AtomicInteger里保存的整数值value。

        发现value和oldValue不同,意味着在CAS之前,另一个线程修改了value。通过这种方式,能识别出是否有人修改。发现value被修改了,就重新读取新的value到oldValue中。

之前线程不安全,内存变了,但是寄存器中的值没有跟着变,所以接下来修改出错

但使用CAS这种方式,就能确保识别出内存的值是不是变了,不变才会进行修改。变了,就会重新读取内存的值。

出现穿插执行就会出现问题。

t2 load的值,不是t1 save的最新值。基于错误的值来进行后续修改,最后结果也就是错了。

使用CAS没有上述问题

确保t2 load到的一定是内存中最新的值,代价“自旋”,消耗更多的cpu

基于CAS实现更灵活的锁,获取到更多的控制权。

一般是用在锁竞争不激烈的场景下。

通过CAS看当前锁是否被某个线程持有,如果这个锁已经被别的线程持有,那么就自旋等待

如果这个锁没有被别的线程持有,那么就把owner设为当前尝试加锁的线程

当owner不为null的时候,循环就会一致执行下去,通过这样的“忙等”来完成等待效果。阻塞式的等,让线程不参与cpu调度了。此处自旋式的等,没有放弃cpu,不会参与到调度,也就没有调度开销了,但缺点是要消耗更多的cpu资源。

三、ABA问题

CAS在使用时,关键要点是要判定当前的内存的值是否是和寄存器里的值是一样的,是一样的就进行修改,不一样就啥也不做。 => 本质上是判定,当前这个代码执行过程中,是否有其他线程穿插进来了。

可能存在的情况,数值本来是0,执行CAS之前,另一个线程把这个值从0->100,又从100->0,不是没有别的线程穿插进来,而是穿插中又把值改回去了。

例子:

假设去银行取钱,初始情况下账户余额1000,要取500,取钱的时候ATM卡了,按了一下没有反应,有按了一下。

但如果t2取完之后,t3又存了500再执行t1

CAS(balance,oldBalance,oldBalance-500)则balance=500

对于ABA问题的解决方案:

1)约定数据变化是单向的(只能增加/只能减少),不能是双向的(即增加有减少)

2)对于本身就必须双向变化的数据,可以给他引入一个版本号(这个数字只能增加不能减少)

CAS本质上是JVM帮我们封装好的,没法直接感知到

JUC java.util.concurrent 放了一些进行多线程编程时有用的类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值