CAS实现原子操作的三个问题

在java中,如果要进行原子操作,我们可以通过加锁或CAS的方式来实现。其中,CAS虽然高效的解决了原子操作,但需要注意其存在的三个问题:ABA问题、自旋时间长开销大、只能保证一个共享变量的原子操作。

一、ABA问题

CAS 在修改变量值时,会先检查该变量的值是否和预期值一致,若一致则修改,引发的ABA问题的情况是:如一个变量初始值为A,被另外一个线程修改成B,再由B修改为A,此时使用CAS进行操作就检查不出变量的变化轨迹,并对该变量修改,这就是ABA问题,其前提条件是“节点可以被循环使用”。

ABA问题的解决办法是在变量前加上版本号,每次变量的修改都将版本号加1,此时 A → B → A 则变成 1A → 2B → 3A。从而避免ABA问题。

JDK 1.5 之后在并发包下也提供了对应的带邮戳的原子类 AtomicStampedReference以解决ABA问题。

/**
 * 原子设置 reference 和 stamp 为给定的更新值,
 * 当且当前的引用== 期望的引用,stamp和期望的stamp相等
 *
 * @param expectedReference the expected value of the reference
 * @param newReference the new value for the reference
 * @param expectedStamp the expected value of the stamp
 * @param newStamp the new value for the stamp
 * @return {@code true} if successful
 */
public boolean compareAndSet(
							 V   expectedReference, // 期望的引用
                             V   newReference, // 新的引用
                             int expectedStamp,// 期望的stamp
                             int newStamp // 新的stamp
                             ) {
    Pair<V> current = pair;
    return
        expectedReference == current.reference &&
        expectedStamp == current.stamp &&
        ((newReference == current.reference &&
          newStamp == current.stamp) ||
         casPair(current, Pair.of(newReference, newStamp)));
}
二、自旋时间长开销大

如果CAS自旋长时间仍不成功,对CPU的开销是非常大的。

三、只能保证一个共享变量的原子操作

CAS可以保证单个共享变量的原子操作,对于多个共享变量,CAS无法保证原子性,当然此时可以使用锁来解决。另外一个方法是:把多个共享变量封装进一个对象,然后通过AtomicReference类保证引用对象之间的原子性。



参考:
1.《Java并发编程的艺术》-Java并发机制的底层实现原理(第2章)
2.《JAVA并发编程实战》,Doug lea

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值