CAS的ABA问题及解决方法

一、什么是ABA问题?

考虑如下操作:

  • 并发1(上):获取出数据的初始值是A,后续计划实施CAS乐观锁,期望数据仍是A的时候,修改才能成功

  • 并发2:将数据修改成B

  • 并发3:将数据修改回A

  • 并发1(下):CAS乐观锁,检测发现初始值还是A,进行数据修改

上述并发环境下,并发1在修改数据时,虽然还是A,但已经不是初始条件的A了,中间发生了A变B,B又变A的变化,此A已经非彼A,数据却成功修改,可能导致错误,这就是CAS引发的所谓的ABA问题。

二、解决办法

ABA问题的优化

ABA问题导致的原因,是CAS过程中只简单进行了“值”的校验,再有些情况下,“值”相同不会引入错误的业务逻辑(例如库存),有些情况下,“值”虽然相同,却已经不是原来的数据了。

优化方向:CAS不能只比对“值”,还必须确保的是原来的数据,才能修改成功。

常见实践:“版本号”的比对,一个数据一个版本,版本变化,即使值相同,也不应该修改成功。

/*
如果当前引用为{@code ==}到预期引用且当前戳记等于预期戳记,则以原子方式将引用和戳记的值设置为给定的更新值。 
*/
源码:
public class AtomicStampedReference<V> {
public boolean compareAndSet(V   expectedReference,
                             V   newReference,
                             int expectedStamp,
                             int newStamp) {
    Pair<V> current = pair;
    return
        expectedReference == current.reference &&
        expectedStamp == current.stamp &&
        ((newReference == current.reference &&
          newStamp == current.stamp) ||
         casPair(current, Pair.of(newReference, newStamp)));
     }

}

三、总结

  • select&set业务场景,在并发时会出现一致性问题

  • 基于“值”的CAS乐观锁,可能导致ABA问题

  • CAS乐观锁,必须保证修改时的“此数据”就是“彼数据”,应该由“值”比对,优化为“版本号”比对

猜你喜欢

转载自blog.csdn.net/yang_154116/article/details/81149942