CAS问题
一.定义
1.1 CAS是什么?
CAS是什么:(compareAndSwap)比较并交换
1.2 代码测试
package InterviewTest;
import java.util.concurrent.atomic.AtomicInteger;
/*
* 1.CAS是什么:<====>compareAndSwap
* 比较并交换
*
* CAS是很多乐观锁的底层实现
*/
public class CASDemo {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(5);
//do something
/*atomicInteger.compareAndSet(5,2021):先比较atomicInteger的值是不是5
* 如果是那么就修改成2021,并返回true
* 如果不是,直接返回false,并不会修改
*/
System.out.println(atomicInteger.compareAndSet(5,2021)
+" 1 current date:"+atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(5,1024)
+" 2 current date:"+atomicInteger.get());
}
}
2.底层原理
2.1 自旋锁
getAndAddInt方法,先执行do-while的循环体,然后判断循环条件,调用compareAndSwapInt方法,如果是期望值,则返回true,并将数据加一,但是有个取反操作,所以while中的值是false,此时就跳出循环;如果不是期望值,则返回false,取反为true,重新进入循环体执行。
假设线程A和线程B两个线程同时执行getAndAddInt操作( 分别跑在不同CPU上) :
1 .AtomicInteger里 面的value原始值为3,即主内存中 AtomicInteger的value为3,根据JMM模型,线程A和 线程B各自持有一份值为3的value的副本分别到各自的 工作内存。
2.线程A通过getntVolatile(var1, var2)拿到value值3, 这时线程A被挂起。|
3.线程B也通过getIntVolatil(var1, var2)方法获取到 value值3,此时刚好线程B没有被挂起并执行 compareAndSwaplnt方法比较内存值也为3,成功修改内 存值为4,线程B打完收工,一切OK。
4.这时线程A恢复,执行compareAndSwaplnt方法比较, 发 现自己手里的值数字3和主内存的值数字4不一致,说明 该值已经被其它线程抢先一步修改过了,那A线程本次 修改失败, 只能重新读取重新来一-遍了。
5.线程A重新获取value值, 因为变量value被volatile 修饰, 所以其它线程对它的修改,线程A.总是能够看到, 线程A继续执行compareAndSwapInt进行比较替换,直到 成功。
2.2 unsafe类
/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
this:代表当前对象。
valueOffset:代表内存偏移量(内存地址)
Unsafe类:是Java自带的原生类,存在于rt.jar这个jar包里面,里面的很多方法都是native方法,这些方法都是调用操作系统底层的数据执行的。
三.CAS的缺点
3.1 自旋锁的存在可能导致循环时间过长
3.2 this对象只有一个,因此只能保证一个共享变量的原子操作。
this:表示当前对象,当前对象只能有一个,如果有多个的 话就要加锁。