目录
一、什么是"原子类"?
二、什么是 CAS ?
三、CAS 的 ABA 问题是什么?
四、如何解决 ABA 问题?
一、什么是"原子类"?
- "原子类"是 Java 标准库提供的 CAS 工具类。存放于 java.util.concurrent.atomic 包中。
- Java提供了各种数据类型的封装类,这些封装类的方法都是"原子"的,没有加锁,但是可以保证线程安全,高效且不涉及线程阻塞等待。
- "原子类" 的类名都为 Atomic 开头,以引用类型结尾,如 AtomicInteger。
- 应注意"原子类"的计算,都是通过调用方法实现的(如自增++,在"原子类"中需要调用 getAndIncrement() 方法)
二、什么是 CAS ?
- CAS 指 compare and swap,表示比较并交换。CAS 是一个原子的 CPU 指令完成的。
- CAS 相当于通过一个”原子“的操作,同时完成”读取内存,比较是否相等,修改内存“这三个步骤,达到”无锁化编程“的目的。
- 比较和交换的是内存和寄存器中的值。
- CAS 的实现本质上需要 CPU 指令的支持,由操作系统和 JVM 进行了封装。
- 使用 CAS 不涉及加锁,不会阻塞。合理使用 CAS 可以保证线程安全。但是由于 CAS 操作涉及操作系统底层,使用不当可能带来风险。
以伪代码的方式理解 CAS:
public void method(){Integer memoryValue;Integer oldValue;Integer newValue;if(CAS(newValue, oldValue, memoryValue)){memoryValue = newValue;}
}
public boolean CAS(Integer newValue, Integer oldValue, Integer memoryValue){if(oldValue == memoryValue){return true;}else {return false;}
}
三、CAS 的 ABA 问题是什么?
CAS 是通过比较当前内存的值是否和寄存器中的值一致,来判断是否为”原子“操作。
但可能出现,B线程先改变了值,又将值再次改回了原值的情况(如先 +1 后马上 -1)。此时在A线程看来,这个值并没有发生改变。这种情况就是 ABA 问题。
ABA 问题通常不会导致程序出错,但特殊情况下也会出现问题。
四、如何解决 ABA 问题?
解决 ABA 问题主要通过两种方式:
- 约定数据变化只能是单调的(只能增或只能减)。
- 引入版本号,版本号只增不减,每次数据发生变化就更改版本号。需要修改数据时,先对比版本号,版本号不一致则认为修改失败。