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