10.CAS 与 原子操作


10. CAS 与 原子操作

10.1 原子性

原子操作就是最小的不可拆分的操作,操作一旦开始,就不能被打断,直到操作完成。

  • 要么全部成功,要么全部失败。
  • 原子操作能保证线程安全性。

10.1.1 Java 中的原子类

java.util.concurrent.automic 包中提供了原子操作类,保证了线程安全性和操作的高效性

  • 基本数据类型原子类:AtomicIntegerAtomicBoolean
  • 数组类型原子类:AtomicIntegerArray, AtomicReferenceArray
  • 引用类型原子类:AtomicReference
    • 把多个变量放在用一个对象里进行 CAS 操作,解决 CAS 的多变量问题
    • AtomicStampedReference 可以解决 ABA 问题
  • 字段类型原子类:AtomicIntegerFieldUpdater

Java 中的原子类在提交数据更改时使用了 CAS 操作,内部实现原理是利用了 CPU 的缓存锁。

10.1.2 处理器实现原子操作

缓存锁:通过锁 CPU 缓存来保证对某个内存地址的操作是原子性的。

10.1.3 Java 实现原子操作

  1. CAS 机制
  2. 锁机制

10.2 CAS

CAS 即 compare and swap,比较并交换

CAS 是无锁编程的一种实现方式,用来实现 自旋锁乐观锁

  • 又叫非阻塞同步

CAS 定义三个值:

  • V : 要更新的变量 var
  • E : 当前线程对变量旧值的预期值 exception
  • N : 变量被更新的值 new

10.2.1 CAS 的更新机制

比较 V 与 E,判断 V 是否被其他线程更改过:

  • 如果 V == E,则设置 V = N
  • 如果 V != E,则说明 V 被其他线程更改过,取消这次更新

10.2.2 CAS 操作的原子性

CAS 是一种系统原语,具有原子性,当多个线程同时使用 CAS 来操作一个变量时,只有一个会更新成功,其他均失败:

  • 失败的线程会被告知失败,此时失败的线程可以尝试重试或者放弃重试
  • 失败并重试被称为 CAS 自旋

10.2.3 CAS 的实现

Java 实现 CAS : Unsafe 类

sun.misc 包下的 Unsafe 类下的几个 native 方法实现了 CAS 操作:

public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x);
CPU 级 CAS 的实现

cmpxchgl CPU 指令实现CAS

10.2.4 CAS 存在的问题

多变量问题

CAS 能完成对单个变量的原子操作,但不能保证多个变量同时操作的原子性

  • 可以通过把多个变量封装成引用类型,通过 AtomicReference 进行 CAS 操作
  • 使用锁,锁同步代码块
ABA 问题

当 CAS 中,变量的值从 A 改到了 B,有改回了 A,则 CAS 会认为变量值没有被改变过。

  • 可以通过版本号机制来解决这一问题。
长时间自旋问题

一直自旋会占用大量的 CPU 资源

  • 使用 pause 指令提升自旋等待循环的性能

10.2.5 CAS 的适用场景

  1. 适用于简单对象的操作,如 boolean,int 等
  2. 适用于冲突少的情况,如果太多线程在自旋,会导致过大的 CPU 开销

文章作者: Yu Yang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yu Yang !
 上一篇
1.Java 中多线程的实现 1.Java 中多线程的实现
1. Java 中多线程的实现主要有三种方案: 继承 Thread 类,并重写 run() 方法 实现 Runnable 接口,并重写 run() 方法 实现 Callable 接口,并重写 call() 方法 其中前两种比较常见。 1
下一篇 
ReentrantLock 与 synchronized ReentrantLock 与 synchronized
ReentrantLock 与 synchronized1. synchronized 与 ReentrantLock 的对比synchronized 与 ReentrantLock 都具备线程重入性,但 synchronized 由 JV
  目录