CAS入门及ABA问题解决

文章主线

CAS----Unsafe类----CAS底层思想----ABA问题----原子引用更新----ABA问题的规避

什么是CAS?

CAS(CompareAndSwap):比较并交换,是一条CPU并发原语

详述:判断内存某个位置的值是否为预期值,如果是则更新值,否则返回false,这个过程是原子的,底层靠UnSafe类来保证原子性;

并发原语体现在Unsafe中的各个方法,调用Unsafe类中的CAS方法,完全依赖于硬件的功能,通过它实现了原子操作

一般应用:循环判断预期值和主存中值直到相等(更新完成)

什么是原语(操作系统)?

原语:由若干条指令组成,用于完成某个功能的一个过程,并且执行过程必须连续,不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成数据不一致性问题

源码解析

过程描述:先比较(用期望值先和主内存中值进行比较,若结果为true(自己修改之前别人未修改),此时更新值 若比较返回false,则放弃修改
调用过程:用户程序----调用compareAndSet(原子类)----compareAndSwap***(Unsafe类)

AtomicInteger(原子整型类的成员方法实现)
public final boolean compareAndSet(int expect, int update) {
     return 
       unsafe.compareAndSwapInt(this, valueOffset, expect,update);
}
//测试
public static void main(String[] args) {
   AtomicInteger f=new AtomicInteger(100);
   System.out.println(f.compareAndSet(100,99)+" "+f.get());
   System.out.println(f.compareAndSet(100,101)+" "+f.get());
}
运行结果:true 99  false 99
分析:线程1和线程2同时从主存中拿到f(100),线程1首先将f更新为99,线程2此时发现值已被更新,则放弃更新f
CAS底层原理
public static void main(String[] args) {
   AtomicInteger f=new AtomicInteger(100);
}
public class AtomicInteger{//(原子整型类的源码)
	private volatile int value;
	public AtomicInteger(int initialValue) {
        value = initialValue;
	}
 	public final int getAndAdd(int d) {
        return Unsafe.getAndAddInt(this, valueOffset, d);
 	}
 }
 class UnSafe{//JVM运行时jar包中
 	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;
	}
 }
过程分析:
var1(this):AtomicInteger对象本身
var2(valueOffset):该对象值的引用地址(内存偏移量)
var4(d):需要变动的num
var5(期望值):通过var1,var2获取的主存中的值
----------假设其他线程也正在修改此值---------------
通过对比期望值与当前与现在主存中的值
若为true,则更新
否则,循环获取期望值,直至更新成功
情景描述

在这里插入图片描述

Unsafe类介绍

来源:JVM的rt运行jar包中,
描述:所有方法大部分都是native修饰的,调用操作系统的底层资源执行相应的任务),是CAS的核心类,Java对底层无能为力,需要通过本地native方法来访问,Unsafe相当于一个后门,基于Unsafe类的内部方法可以直接操作特定内存中的数据,因此Java中CAS操作的执行依赖于Unsafe中的方法

CAS是比较并交换,凭什么可以保证原子性?

靠的是Unsafe类,因为Unsafe根据内存地址直接操作数据所以可保证原子性

CAS与synchronized

synchronized:一致性得到保证,但是并发性下降
CAS:一致性、并发性得到保证

不足之处:
1、若CAS失败,则会一直尝试,CPU开销很大
2、当对一个共享变量执行操作时,可使用循环CAS的方式来保证原子操作,有多个共享变量需考虑加锁
3、引出ABA问题

什么是原子类的ABA问题?

ABA问题:
CAS算法实现的重要前提是取出内存中某时刻的数据并在当下时刻 比较并交换,那么在这个 时间差 内数据可能会发生 多次变化
情景举例:
线程1从内存中取出A,这时候线程2也从内存中取出A,并且线程2进行了一些操作将值变成了B,然后线程2又将值改回了A,这时候线程1进行CAS操作发现内存中依然是A,然后线程1操作成功

原子更新引用(原子引用类更新值)
//AtomicReference是一个泛型类
public static void main(String[] args) {
	User u1=new User("张三",21);
	User u2=new User("李四",22);
	AtomicReference<User> a=new AtomicReference<>();
	a.set(u1);
	System.out.println(a.compareAndSet(u1, u2)+"  "+a.get().toString());
	System.out.println(a.compareAndSet(u1, u2)+"  "+a.get().toString());
}
结果分析:
      true   [name:李四,age:22]
      false  [name:李四,age:22]
ABA问题的解决?

原子引用+版本号机制(类似于时间戳)
jdk实现的带时间戳的原子引用AtomicStampedReference,在每次更新时要判断期望值和版本号两者是否都未发生变化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值