简介
说明
本文介绍Java中的CAS的原理,优点和缺点。
CAS,Compare And Swap,即比较并交换。
CAS性能很高,适合于高并发场景。
CAS是JUC的基础
Doug lea大神在同步组件中大量使用CAS实现了Java多线程的并发操作,CAS是整个JUC(java.util.concurrent)的基石。
以下组件都用到了CAS
- AQS同步组件
- Atomic原子类操作
- jdk8的ConcurrentHashMap使用CAS + Synchronized。
CAS原理
CAS是一种基于锁的操作,而且是乐观锁。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。若内存地址里面的值和A的值是一样的,就将内存里面的值更新成B。
CAS是通过无限循环来获取数据的,一旦检测到冲突产生,就重试当前操作直到没有冲突。
若在第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程自旋,直到某一次循环时地址里的值没有被修改。
CAS优点
CAS是乐观锁,且一直自旋等待锁,所以性能很高。
CAS缺点
CAS缺点有三个:CPU开销大;ABA问题;只能保证一个共享变量原子操作。
缺点 | 说明 | 解决方法 |
CPU开销大 | 如果自旋CAS长时间地不成功,则会给CPU带来非常大的开销。 | 在JUC中有些地方就限制了CAS自旋的次数,例如BlockingQueue的SynchronousQueue。 |
ABA问题 | 如果一个值原来是A,变成了B,然后又变成了A,在CAS检查时会发现没有改变,但实际它已经改变,这就是ABA问题。大部分情况下ABA问题不会影响程序并发的正确性。 | 每个变量都加上一个版本号,每次改变时加1,即A —> B —> A,变成1A —> 2B —> 3A。 Java提供了AtomicStampedReference来解决。AtomicStampedReference通过包装[E,Integer]的元组来对对象标记版本戳(stamp),从而避免ABA问题。 |
只能保证一个共享变量原子操作 | CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。 | 比如需要保证3个变量共同进行原子性的更新,就不得不使用Synchronized了。 还可以考虑使用AtomicReference来包装多个变量,通过这种方式来处理多个共享变量的情况。 |
请先
!