什么是CAS?
CAS全称 Compare And Swap ,比较与交换,是乐观锁的主要实现方式。CAS在不使用锁的情况下实现 多线程之间的变量同步。 ReentrantLock 内部的AQS和原子类内部都使用了CAS。
CAS算法涉及到三个操作数:
- 需要读写的内存值V。
- 进行比较的值A。
- 要写入的新值B。
只有当V的值等于A时,才会使用原子方式用新值B来更新V的值,否则会继续重试直到成功更新值。
以 AtomicInteger 为例, AtomicInteger 的 getAndIncrement() 方法底层就是CAS实现,关键代码是 compareAndSwapInt(obj, offset, expect, update) ,其含义就是,如果 obj 内的 value 和 expect 相等,就证明没有其他线程改变过这个变量,那么就更新它为 update ,如果不相等,那就会继 续重试直到成功更新值。
CAS存在的问题?
CAS 三大问题:
1. ABA问题。CAS需要在操作值的时候检查内存值是否发生变化,没有发生变化才会更新内存值。但 是如果内存值原来是A,后来变成了B,然后又变成了A,那么CAS进行检查时会发现值没有发生变 化,但是实际上是有变化的。ABA问题的解决思路就是在变量前面添加版本号,每次变量更新的时 候都把版本号加一,这样变化过程就从 A-B-A 变成了 1A-2B-3A 。 JDK从1.5开始提供了AtomicStampedReference类来解决ABA问题,原子更新带有版本号的引用类 型。
2. 循环时间长开销大。CAS操作如果长时间不成功,会导致其一直自旋,给CPU带来非常大的开销。
3. 只能保证一个共享变量的原子操作。对一个共享变量执行操作时,CAS能够保证原子操作,但是对 多个共享变量操作时,CAS是无法保证操作的原子性的。 Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在 一个对象里来进行CAS操作。