前言:
众所周知,B站是全中国最大的在线学习平台,此次学习打卡的教程来自【狂神说】与【寒食君】两位B站up主,欢迎大家一键三连🚀
学习视频来源:
博客回顾:
前置知识:学习JUC前需要对java的多线程有一定的掌握。
学习视频:
详细资料可参考博客:狂神说Java之多线程详解<全网最全(代码+笔记)>
0. 学习方法
源码+官方文档:
其实官方文档就是源码编译出来的,其本质还是看源码,不过文档会比较方便学习
- 只有多看源码,多研究文档才会进步
- Java英文文档可以通过点击查看源码获取
- Java1.8中文文档(中文 – 谷歌版)
19. 理解CAS
什么是CAS :
CAS 是 Compare And Swap的简称,从字面上理解就是比较并更新,简单来说:从某一内存上取值V,和预期值A进行比较,如果内存值V和预期值A的结果相等,那么我们就把新值B更新到内存,如果不相等,那么就重复上述操作直到成功为止。
在 Java的原子类中,有对cas的封装进行应用:此处用 AtomicInteger
举例
public class CAS_Demo {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//CAS的封装体现:compareAndSet 比较并赋值
//比较当前值是否为2020? set 2021,return true : do nothing,return false
System.out.println(atomicInteger.compareAndSet(2020, 2021));//true
System.out.println(atomicInteger.get());//此时为2021
//获取值并自增
atomicInteger.getAndIncrement();//自增后为 2022
System.out.println(atomicInteger.compareAndSet(2021, 2033));//false
System.out.println(atomicInteger.get());// 2022
}
}
点击查看AtomicInteger
的源码:
直接通过Unsafe
类调用底层 CAS方法
//compareAndSet
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//getAndIncrement
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
getAndAddInt
方法详解:
通过一定的轮询,也就是后面介绍的自旋锁:
CAS锁其又称作Java的乐观锁,但是我们可以看到其实质上是没有上🔒的,只是赋值的过程前多了一个比较的方法,因此可能引起一定的ABA问题:
[狸猫换太子] 如果另一个线程修改V值假设原来是A,先修改成B,再修改回成A。当前线程的CAS操作无法分辨当前V值是否发生过变化。
举个栗子:
在你非常渴的情况下你发现一个盛满水的杯子,你一饮而尽。之后再给杯子里重新倒满水。然后你离开,当杯子的真正主人回来时看到杯子还是盛满水,他当然不知道是否被人喝完重新倒满。
public class CAS_Demo {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
// 我们想把数字改成6666
// ============== 捣乱的线程 ==================
atomicInteger.compareAndSet(2020, 2021);
System.out.println("such a fool...");
atomicInteger.compareAndSet(2021, 2020);
// ============== 期望的线程 ==================
System.out.println(atomicInteger.compareAndSet(2020, 6666));
System.out.println(atomicInteger.get())