Java 中各种锁的学习

116 阅读2分钟

乐观锁与悲观锁

同样都是为了解决因为并发操作而导致同步资源不正确的方案

乐观锁

在使用同步资源时不考虑别的线程修改数据,只有在更新数据时才去判断有没有别的线程修改了该数据,如果有则做出相应的操作,如果没有则更新资源

悲观锁

在使用同步资源时对资源进行上锁,不允许其他线程访问该资源。

适用的场景

悲观锁

  • 频繁写操作

乐观锁

  • 频繁读操作

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 长时间不成功
  • 只能保证一个共享变量的原子操作。