Java的CAS乐观锁原理解析(2)

对一个共享变量执行操作时,CAS能够保证原子操作,但是对多个共享变量操作时,CAS是无法保证操作的原子性的。
Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里来进行CAS操作。

ABA问题(无法体现数据的变动)

CAS需要在操作值的时候检查内存值是否发生变化,没有发生变化才会更新内存值。但是如果内存值原来是A,后来变成了B,然后又变成了A,那么CAS进行检查时会发现值没有发生变化,但是实际上是有变化的。
ABA问题的解决思路就是在变量前面添加版本号,每次变量更新的时候都把版本号加一,这样变化过程就从“A-B-A”变成了“1A-2B-3A”。

JDK从1.5开始提供了AtomicStampedReference类来解决ABA问题,具体操作封装在compareAndSet()中。
compareAndSet()首先检查当前引用和当前标志与预期引用和预期标志是否相等,如果都相等,则以原子方式将引用值和标志的值设置为给定的更新值。
不过目前来说这个类比较”鸡肋”,大部分情况下 ABA 问题并不会影响程序并发的正确性,如果需要解决 ABA 问题,使用传统的互斥同步可能比原子类更加高效。

只能保证一个共享变量的原子操作。对一个共享变量执行操作时,CAS能够保证原子操作,但是对多个共享变量操作时,CAS是无法保证操作的原子性的。
Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里来进行CAS操作。

Java 8 更新

当然这都是由 Doug Lea 大佬亲自为 Java 操刀

更新器 DoubleAccumulator

Java的CAS乐观锁原理解析

LongAccumulator

Java的CAS乐观锁原理解析

计数器 DoubleAdder

Java的CAS乐观锁原理解析

LongAdder

Java的CAS乐观锁原理解析


计数器增强版,高并发下性能更好
频繁更新但不太频繁读取的汇总统计信息时使用分成多个操作单元,不同线程更新不同的单元

只有需要汇总的时候才计算所有单元的操作

Java的CAS乐观锁原理解析


T1执行后,A 变成了B

Java的CAS乐观锁原理解析


T3又开始执行了, B变成了A

T2开始执行, A变成了C

问题点:

经历的A -> B -> A过程,但是对于线程2,无法感知数据发生了变化

Java的CAS乐观锁原理解析

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/eb437e8c79272f0dc295f73869030b7b.html