1、有两个线程同时修改一个变量的值,线程1、线程2,都更新变量值,将变量从A更新为B
2、首先线程1获得到CPU时间片,线程2由于某些原因原因发生等待,线程1进行比较更新,CAS
(CompareAndSwap),成功将变量的值从A更新到B
3、更新完毕后,恰好又有线程3进来想要把变量的值从B更新到A,线程3进行比较更新,成功将变量的值从B更新为A
4、线程2获得到CPU时间片,然后进行比较更新,发现值是预期的A,然后又更新成了B,但是线程1并不知道该值已经从A-->B-->A这个过程,这就是ABA问题。
如何避免ABA问题?
可以通过加版本号或者时间戳解决,或者保证单向递增或递减就不会存在此类问题,atomic包下的AtomicStampedReference类的CompareAndSet方法首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该标志的值设置给定的更新值
package com.ws.cas;
import java.util.concurrent.atomic.AtomicInteger;
public class CASDemo {
//CAS compareAndSet:比较并交换!!!
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//对于我们平时写的SQL来说:乐观锁!
//第一个参数是期望、第二个参数是更新
//public final boolean compareAndSet(int expect, int update)
//如果我期望的值达到了,那么就更新,否则就不更新 CAS是CPU的并发原语
//乱搞线程
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(2021, 2020));
System.out.println(atomicInteger.get());
//期望的线程
System.out.println(atomicInteger.compareAndSet(2020, 6666));
System.out.println(atomicInteger.get());
}
}
CAS导致的其他问题?
- 只能保证一个共享变量的原子操作
- 自旋CAS如果长时间不成功,会给CPU带来开销大的问题