CAS: Compare and swap 比较和交换
在指令的级别,保证该操作的原子性。
原理
如果这个内存地址的值是我所期望的值,那么就把它设成新值。
比如,如果内存地址为100的位置的值是1,我想把值改为2,那么CAS赋值操作就是这样的:如果内存地址为100的位置值是1,那么就把值设为2.所以如果其他线程在此之前把值改为了3,则这个CAS赋值失败。因此就出现了自旋(死循环)CAS赋值操作(每次CAS期望的值都从内存中现取一份)。
基于这样的特性,CAS又可用于乐观锁。
悲观锁是每次执行代码都是先加锁再执行,所以叫悲观(认为竞争太激烈,直接加锁吧);
乐观锁是每次执行代码先尝试,不行的话再继续尝试,所以叫乐观(认为竞争不激烈,可以尝试)。
CAS存在的问题
- CAS长期不成功,则一直死循环。
- 版本问题(ABA问题)。比如CAS期望的值是A,其他线程把A改成B又改成A,CAS操作也会成功,但是并不意味着值没有发生过改变。解决方法就是加一个版本戳:A1->B2->C3,让CAS期望A1就好了。
jdk中的原子操作类 Atomic
解决版本问题有两个Atomic:
- AtomicMarkableReference,isMarked():boolean ,只关心有没有动过
- AtomicStampedReference ,getStamp():int,可以获取版本戳,关心动过几次