并发之CAS的举例详解

CAS原理举例子通俗解释

CAS的应用场景:

无论是ReenterLock内部的AQS,还是各种Atomic开头的原子类,内部都应用到了CAS

java并发过程中,要做到线程安全的考虑:

1.sychronized:这种独占锁是采用悲观锁的方式去做的,多个线程去请求资源时会阻塞进行,以保证线程安全。

2.volatile关键字:它只能保证内存可见性不能保证原子性,而且对于有多个共享资源的情况下就无法去保证线程安全了,还是要采用sychronized去做。

3.cas是乐观锁的一种实现,就是不去加锁达到线程安全的目的,所谓乐观就是认为永远不会发生多个线程对资源的请求永远不会发生冲突,如果有冲突再去解决(一直重试,直到成功)。

cas的解释

我们举一个例子来说:拿基于cas实现的juc包下的一个可进行原子操作的原子类AtomicInteger来说:

jdk1.8.0_202\jre\lib\rt.jar!\java\util\concurrent\atomic\AtomicInteger.class

以上是它再jdk中的path

一、类的构成

在这里插入图片描述

由上面的源码可以看到几个关键点:

1.静态成员变量中获取到了Unsafe类的实例(这是CAS能够实现原子操作的核心类)

2.在静态代码块中通过反射获取到了当前对象中的value属性,并将他传入了unsafe的objectFieldOffset方法中(该方法是native方法)。static块的加载发生于类加载的时候,是最先初始化的,这时候我们调用unsafeobjectFieldOffsetAtomic类文件中获取value的偏移量,那么valueOffset其实就是记录value的偏移量的(可以根据这个偏移量算出正真的内存地址)。

value就是这个AtomicInteger变量的值,它是由volatile关键字修饰的以此保证内存可见性,我们可以通过AtomicInteger类的get()方法获取到value的值。

二、取一个方法来说明CAS

AtomicInteger类中一个加法运算的方法的源码,对value进行加delta操作:

在这里插入图片描述

它调用了unsafe对象的getAndAddInt方法,传入的参数包括这个AtomicInteger对象本身,之前算好的偏移量(依靠它可以获得value真实的内存地址),以及要加的值。看一下unsafe的getAndAddInt方法:

在这里插入图片描述

这里假如A线程获取到Var5的最新值为10打算通过compareAndSwapInt()去修改值为11时,B线程先一步修改了内存中的value为11,这时候A通过compareAndSwapInt()方法先去传入的对象中根据偏移量取出内存中的最新值和之前取得Var5作比较**(这里的Var5就是CAS中所说的旧的预期值,内存中重新取得值就是内存中的值)**,此时肯定不相等,那么就返回false,让它进行自旋操作重新取值给Var5赋值,再进行compareAndSwapInt()方法。

这就是CAS的核心思想:每次获取内存中的值与旧的预期值作比较,如果不一致就重新去算旧的预期值,如果一致就做CAS(比较交换)操作来达到原子操作的目的。这里的比较交换并不是两个操作,它在native方法中是借助cpu指令来进行的所以一定是原子操作。

compareAndSwapInt()方法:一个native方法。

在这里插入图片描述

Unsafe类中的方法在其他的地方的用途

1.AQS框架中,在独占资源的情况下,多个线程去请求资源如果资源被占有就要把这些线程封装成node节点存放在一个CLH队列中,因为要按顺序去排队获取资源,在没有排到自己的时候就不要让线程一直运行了,这时候是通过unsafe的park()方法让这些线程进入到waiting状态的,

2.在面试中如果可以用unsafe的park和unpark方法来写出线程间的通信的编程题目是加分项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值