如果本文有错,希望在下面的留言区指正。
在之前的一些源码分析中,为了实现并发,Doug Lea 大佬在Java8及以上,大量使用了 CAS 操作。JDK 提供的关于 CAS 原子操作的类在下面工具包里面:
JDK为Java基本类型都提供了CAS工具类。
CAS
已 为例,进行分析:
如上面的源码,对于 CAS 操作,这里会出现3个值,expect、update、value。只有当expect和内存中的value相同时,才把value更新为update。
ABA 问题
假设如下事件序列:
线程 1 从内存位置V中取出A。
线程 2 从位置V中取出A。
线程 2 进行了一些操作,将B写入位置V。
线程 2 将A再次写入位置V。
线程 1 进行CAS操作,发现位置V中仍然是A,操作成功。
尽管上面的CAS操作成功了,数据也没有问题,但是程序失去了对数据变换的敏感性,不知道数据的变换。
比如发生扣款/收款行为时,应当收到短信通知这个场景,
1、时刻1 : 500元
2、时刻2:转给了 A 10 元 490 元
3、时刻3:B 转入 10 元 500 元
应当收到两条短信,而不是最后我的账户余额没有变化,就一条短信都收不到
上面的图片来源不知道是谁的,只是在一个技术群里和别人聊CAS时别人发的。
解决方法
JDK为了解决 ABA 问题,提供了两种方法
AtomicStampedReference
JDK 为了解决 ABA 问题,提供了一些方法,如 ,在版本的更新过程中,添加了一个 邮戳来标记数据的版本。
具体关于 CAS 操作源码
如上面所示,在更新的过程中,除了比较内存中value的预期值,还比较了 stamp 的预期值,只有两者都相同的时候,才会把内存中的值更新掉。
AtomicMarkableReference
和 功能相似,但 描述更加简单的是与否的关系。它的定义就是将状态戳简化为true|false。如下:
领取专属 10元无门槛券
私享最新 技术干货