CAS原理:
CAS全称Compare and Swap,比较并交换,主要是通过处理器的指令来保证操作的原子性.
CAS的思想比较简单,主要涉及到三个值:
- 当前内存值V
- 预期值(旧的内存值)A
- 即将更新的内存值B
当执行CAS指令时,只有当内存值V等于预期值A时,才会将内存值V修改为更新值B,否则就不会执行更新操作。
CAS主要使用在一些需要上锁的场景充当乐观锁解决方案,一般在一些简单且要上锁的操作但又不想引入锁场景,这时候来使用CAS代替锁。
CAS有什么缺点:
1.ABA问题:
ABA问题是指有一个线程t1在进行CAS操作时,其他线程t2将变量A改成了B,然后又将其改成A,这时候t1发现A并没有改变,因此进行了交换操作,由于在交换操作进行前变量A其实是有变化的,只不过最终又修改回A了,此A非彼A,这时候进行交换操作在一些业务场景下很可能要出问题,要解决ABA问题有2种方案。
方案一:
在对变量进行操作的时候给变量加一个版本号,每次对变量操作都将版本号加1,常见在数据库的乐观锁中可见。
方案二:
Java提供了相应的原子引用类AtomicStampedReference,他加入了预期标志和更新后标志两个字段,更新时不光检查值,还要检查当前的标志是否等于预期标志,全部相等的话才会更新。
2.自旋带来的消耗:
CAS自旋如果很长时间都不成功,这会给CPU带来很大的开销。
解决方案:
1、代码层面破坏掉for循坏,设置合适的循环次数。
2、使用JVM能支持处理器提供的pause指令来提升效率,它可以延迟流水线执行指令,避免消耗过多CPU资源。
3.CAS只能单变量:
对于一个共享变量,可以使用CAS方式来保证原子操作,但是当多个共享变量时,那就无法使用CAS来保证原子性。JDK1.5开始,提供了AtomicReference类来保证引用对象之前的原子性,就可以把多个变量放在一个对象里来进行CAS操作。
在JDK1.5中新增的java.util.concurrent(JUC),就是建立在CAS之上的,一般来说CAS这种乐观锁适合读多写少的场景。
本文共 607 个字数,平均阅读时长 ≈ 2分钟
评论 (0)