乐观锁与悲观锁
同样都是为了解决因为并发操作而导致同步资源不正确的方案
乐观锁
在使用同步资源时不考虑别的线程修改数据,只有在更新数据时才去判断有没有别的线程修改了该数据,如果有则做出相应的操作,如果没有则更新资源
悲观锁
在使用同步资源时对资源进行上锁,不允许其他线程访问该资源。
适用的场景
悲观锁
- 频繁写操作
乐观锁
- 频繁读操作
CAS技术 乐观锁实现的原理
全称 Compare And Swap(比较与交换)无锁算法,在线程没有阻塞的情况下实现多线程变量同步。
三个操作数
- N 需要读写的内存内容
- C 进行比较的值
- W 需要写入的值
当且仅当 N 等于 C 时,CAS 通过原子的方式将 W 写入 N(比较和更新为一个原子操作),否则不进行任何操作。
AtomicInteger类
Java中该类通过 CAS 实现了乐观锁,存放在 java.util.concurrent 包中
各个属性
根据定义推出各个属性的作用
- unsafe:获取并操作的内存
- valueOffset:存储 value 在 AtomicInteger 中的偏移量
- value:存储 AtomicInteger 的 int 值,该属性使用 volatile 修饰,保证在线程间可见
CAS 的实现
可以看到方法 incrementAndGet 实际上就是在进行三个操作,更新与写操作被封装在 compareAndSwapInt 方法中。
CAS 存在的问题
- ABA 问题
如果内存值原来为 A,先更新为 B,接着又更新为 A,当 CAS 进行检查时会认为值没有进行改变,然而实际上进行了改变。- 解决方法:在变量前添加版本号,每次更新都改变版本号
- 循环时间长开销大 如果写操作过于频繁,会导致 CAS 长时间不成功
- 只能保证一个共享变量的原子操作。