15.CAS,原子引用
深入理解CAS
什么是CAS
public class Demo01 {
//CAS compareAndSet:比较并交换
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//如果期望值达到了就更新,否则就不更新
atomicInteger.compareAndSet(2020, 2021);
System.out.println(atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(2020, 2022));//false
}
}
Unsafe类


CAS:比较当前工作内存中的值和主内存中的值,如果是期望的。那么则执行操作!不是就一直循环(自旋锁)
缺点:
- 循环会耗时
- 一次性只能保证一个共享变量的原子性
- 存在ABA问题
CAS:ABA问题(狸猫换太子)

图示:A的值其实已经是改变过了的,但左边线程不知道
public class Demo01 {
//CAS compareAndSet:比较并交换
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//如果期望值达到了就更新,否则就不更新
//捣乱的线程,2020->2021->2020
atomicInteger.compareAndSet(2020, 2021);
System.out.println(atomicInteger.get());
atomicInteger.compareAndSet(2021, 2020);//false
System.out.println(atomicInteger.get());
//期望的线程
atomicInteger.compareAndSet(2020, 6666);
System.out.println(atomicInteger.get());//6666
}
}
原子引用
带版本号的原子操作,解决了ABA的问题,乐观锁的思想。干什么都不加锁,比较版本
public class Demo02 {
public static void main(String[] args) {
//初始值,版本
AtomicStampedReference<Integer> reference = new AtomicStampedReference<>(10, 1);
new Thread(() -> {
System.out.println("A1==>" + reference.getStamp());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
reference.compareAndSet(10, 20, reference.getStamp(), reference.getStamp() + 1);
System.out.println("A2==>" + reference.getStamp());
reference.compareAndSet(20, 10, reference.getStamp(), reference.getStamp() + 1);
System.out.println("A3==>" + reference.getStamp());
}, "A").start();
//和乐观锁原理相同
new Thread(() -> {
int stamp = reference.getStamp();
System.out.println("B1==>" + stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
//B线程获取到的值虽然是初始值10,但版本显然不是初始版本1,已经为3,是被修改过的,所以这里修改失败
System.out.println(reference.compareAndSet(10, 100, stamp, stamp + 1));
System.out.println("B2==>" + reference.getStamp());
}, "B").start();
}
}

浙公网安备 33010602011771号