比较并交换
在学习CAS之前,我们先了解一下JMM。什么又是JMM?我只知道JVM。这他妈是啥东西啊?
JMM:java内存模型。jmm是一种抽象的概念,并不真实存在,它描述的是一种规范,通过这种规范定义了程序中的各个变量的访问形式。(仔细读,还是能读懂的)
JMM关于同步的规定(仔细读):
1.线程解锁前,必须把共享变量的值刷新回主内存
2.线程加锁前,必须读取主内存的最新值到自己的工作内存
3.加锁解锁是同一把锁
知道看不懂,开始白话文解释!
JVM我们的java虚拟机运行程序的时候,是以线程为最小刻度的。而每个线程创建的时候,jvm就会为这个线程创建一个工作内存,该工作内存是私有的,只能被当前线程所访问。
而JMM内存模型中规定:所有的变量都储存在主内存中,所有线程都能访问,但线程对变量的任何操作(读取赋值等)都必须在工作内存中进行,首先要将主内存中的变量拷贝到自己的工作内存中,然后才能对变量进行操作,操作完成后再讲变量写会主内存中。
看不懂没事,先上一段代码
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(5);
boolean success = atomicInteger.compareAndSet(5,10);
System.out.println(success);
System.out.println(atomicInteger.get());
}
那么这段代码是什么意思呢?compareAndSet方法是干啥的,其中的两个参数是干嘛的?
compareAndSet两个参数:
还是看不懂,好,我们梳理一下程序进来的时候发生了什么事情。
atomicInteger.getAndIncrement()
上面这行代码就是和我们平时的i++一样
我们知道i++在底层是线程不安全的,它被分为了3步
那为什么atomicInteger.getAndIncrement()就可以实现线程 安全呢?
我们点进去看一下getAndIncrement方法:
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
这里我们看到是调用unsafe类中的getAndAddInt方法,并传了3个参数:
这里引出两个问题:什么是unsafe类?什么是内存偏移量?
我们继续往下看,最重要的来了。
先看看unsafe和valueOffset在AtomicInteger 中的声明:
Unsafe类是CAS的核心类,jdk自带。由于java方法无法直接访问底层系统,需要通过本地方法(native修饰)来方法,Unsafe相当于一个后门,该类的所有方法都是native修饰,可以直接获取到特定内存中的数据。
valueOffset内存偏移量就相当于C中的指针,Unsafe类通过valueOffset去定位数据在内存中的位置从而获得数据
这个时候我们再看这个方法:
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
意思就很明确了:我要拿到当前对象(atomicInteger )的内存地址值(valueOffset),然后进行内存意义上的+1操作!
好!我们现在进去unsafe类看看getAndAddInt这个方法是什么样的:
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
三个参数:
运行步骤:
CAS缺点,以及ABA问题和解决办法.
好了 基本已经讲完,欢迎大家评论区指出不足,一起学习进步!
大家看完了点个赞,码字不容易啊。。。