CAS比较并交换
文章目录
-
- CAS 伪代码
- 两种典型的不是“原⼦性”的代码:
-
- `check and set`(if 判定然后设定值)
- `read and update` (i++)
- CAS 是怎么实现的?
- CAS 有哪些应用?
-
- 实现原子类
- 实现自旋锁
- CAS 的 ABA 问题
-
- ABA 场景描述
- ABA 问题引来的 BUG
- 解决方案
- CAS 的优缺点
CAS(Compare-And-Swap,比较并交换)是一种用于实现多线程同步的无锁编程技术,主要用于解决并发编程中的数据一致性问题。它是一种原子操作,通常用于实现线程安全的算法,而无需使用传统的锁机制(如互斥锁)。
在并发编程中,代码的“原子性”指的是一个操作在执行过程中不会被其他线程中断,即要么全部完成,要么全部不完成。
如果一个操作不是原子性的,那么在多线程环境中可能会导致数据不一致或其他并发问题。
CAS 伪代码
这里的代码不是原⼦的,真实的 CAS 是⼀个原⼦的硬件指令完成的,这个伪代码只是辅助理解 CAS 的⼯作流程。
boolean CAS(address, expectValue, newValue) {
if (&address == expectedValue) {
&address = newValue;
return true;
} else {
return false;
}
}
- CAS操作涉及三个参数:
- 内存位置(address):要更新的变量在内存中的地址。
- 预期值(expectedValue):期望内存位置当前的值。
- 新值(newValue):如果内存位置的值等于预期值,则将该位置更新为新值。
- CAS 的操作流程如下:
- 比较内存中的值
address
和预期值expectedValue
- 如果相等,则将内存中的值
address
更新为新值newValue
,并返回成功; - 如果不相等,则不进行任何修改,并返回失败。
- 比较内存中的值
注意:
当多个线程同时对某个资源进⾏ CAS 操作,只能有⼀个线程操作成功,但是并不会阻塞其他线程,其他线程只会收到操作失败的信号。
CAS 可以视为是⼀种乐观锁,或者可以理解成 CAS 是乐观锁的⼀种实现⽅式。
两种典型的不是“原⼦性”的代码:
check and set
(if 判定然后设定值)
public class NonAtomicCheckAndSet {
private int value;
public void setValueIf(int expectedValue, int newValue) {
if (value == expectedValue) {
// 非原子性检查
value = newValue; // 非原子性更新
}
}
public int getValue() {
return value;
}
public static void main(String[] args) {
NonAtomicCheckAndSet example = new NonAtomicCheckAndSet();
example.setValueIf(0, 1); // 假设value初始值为0
}
}
问题:
在多线程环境下,if
判断和赋值操作不是原子性的。可能存在以下问题:
- 线程1读取
value
为0,判断条件成立。 - 在线程1执行
value = newValue
之前,线程2将value
修改为其他值。 - 线程1继续执行
value = newValue
,此时value
的值可能已经不符合预期条件了。
解决方案:
使用AtomicInteger
的compareAndSet
方法来实现原子性操作:
public