CAS的ABA问题详解
- ABA问题
- 在多线程场景下CAS会出现ABA问题,关于ABA问题这里简单科普下,例如有2个线程同时对同一个值(初始值为A)进行CAS操作,这三个线程如下
- 1.线程1,期望值为A,欲更新的值为B
- 2.线程2,期望值为A,欲更新的值为B
- 线程1抢先获得CPU时间片,而线程2因为其他原因阻塞了,线程1取值与期望的A值比较,发现相等然后将值更新为B,然后这个时候出现了线程3,期望值为B,欲更新的值为A,线程3取值与期望的值B比较,发现相等则将值更新为A,此时线程2从阻塞中恢复,并且获得了CPU时间片,这时候线程2取值与期望的值A比较,发现相等则将值更新为B,虽然线程2也完成了操作,但是线程2并不知道值已经经过了A->B->A的变化过程。
- ABA问题带来的危害:
- 小明在提款机,提取了50元,因为提款机问题,有两个线程,同时把余额从100变为50
- 线程1(提款机):获取当前值100,期望更新为50,
- 线程2(提款机):获取当前值100,期望更新为50,
- 线程1成功执行,线程2某种原因block了,这时,某人给小明汇款50
- 线程3(默认):获取当前值50,期望更新为100,
- 这时候线程3成功执行,余额变为100,
- 线程2从Block中恢复,获取到的也是100,compare之后,继续更新余额为50!!!
- 此时可以看到,实际余额应该为100(100-50+50),但是实际上变为了50(100-50+50-50)这就是ABA问题带来的成功提交。
二、解决办法
ABA问题的优化(AtomicStampedReference)
- ABA问题导致的原因,是CAS过程中只简单进行了“值”的校验,再有些情况下,“值”相同不会引入错误的业务逻辑(例如库存),有些情况下,“值”虽然相同,却已经不是原来的数据了。
- 优化方向:CAS不能只比对“值”,还必须确保的是原来的数据,才能修改成功。
- 解决方法: 在变量前面加上版本号,每次变量更新的时候变量的版本号都+1,即A->B->A就变成了1A->2B->3A。
- 常见实践:“版本号”的比对,一个数据一个版本,版本变化,即使值相同,也不应该修改成功。
- CAS的应用场景:
- 应用于简单的数据计算
- 适合线程冲突少的场景