Skip to main content

CAS

非阻塞同步,Compare-And-Swap,先比较再交换 通过比较共享变量的当前值与期望值,确定读写之间是否有竞争线程干预,实现无锁的并发操作 类似sql里面的 update set f1 = 2 from t1 where f1 = 1

大致流程

  • 三个操作数:内存位置(V),预期原值(A),新值(B)
  • 先读A,进行一些操作后,准备代写入的B,比较A和当前的V,若相等,就认为读A之后没有其他线程干预,把B写入到V的位置

java中的原语

unsafe类中的

  • compareAndSwapObject
  • compareAndSwapInt
  • compareAndSwapLong

ABA问题

旧的预期值A在多次修改之后修改回了A

解决:通过控制变量值的版本来保证正确性,每次修改版本+1
如AtomicStampedReference

示例

import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampedReferenceExample {
public static void main(String[] args) {
// 初始值为100,初始版本号为0
AtomicStampedReference<Integer> atomicStampedRef = new AtomicStampedReference<>(100, 0);

// 模拟线程A,先获取当前的值和版本号
int[] stampHolder = new int[1];
int initialValue = atomicStampedRef.get(stampHolder);
int initialStamp = stampHolder[0];

// 模拟线程B,修改值并更新版本号
boolean success = atomicStampedRef.compareAndSet(initialValue, 200, initialStamp, initialStamp + 1);
System.out.println("Thread B updated value: " + success);

// 模拟线程C,尝试使用旧的版本号进行CAS操作,此时会失败
success = atomicStampedRef.compareAndSet(initialValue, 300, initialStamp, initialStamp + 1);
System.out.println("Thread C updated value: " + success);

// 模拟线程D,使用新的版本号进行CAS操作,此时会成功
int[] newStampHolder = new int[1];
int newValue = atomicStampedRef.get(newStampHolder);
int newStamp = newStampHolder[0];
success = atomicStampedRef.compareAndSet(newValue, 300, newStamp, newStamp + 1);
System.out.println("Thread D updated value: " + success);
}
}