CAS机制专篇,超详细讲解!(比较与交换,compareAndSwap,CAS原理,Unsafe是什么?valueOffset是什么?CAS的缺点,CAS的应用场景,ABA问题,ABA问题的解决办法)

本文详细介绍了CAS(CompareAndSwap)无锁算法的工作原理、使用场景及其在Java中的实现,包括AtomicInteger类的源码分析。同时,文章探讨了CAS的优缺点,如CPU开销大、只能保证单个变量原子操作以及ABA问题,并给出了ABA问题的解决方案。最后,对比了CAS与synchronized在不同并发情况下的适用性。
摘要由CSDN通过智能技术生成

CAS专篇

前言

​ 日常编码过程中,基本不会直接用到 CAS 操作,都是通过一些JDK 封装好的并发工具类来使用的,在 java.util.concurrent 包下。但是面试时 CAS 还是个高频考点,所以呀,你还不得不硬着头皮去死磕一下这块的技能点,总比一问三不知强吧?

一、为什么要用无锁?

​ 我们一想到在多线程下保证安全的方式头一个要拎出来的肯定是锁,不管从硬件、操作系统层面都或多或少在使用锁。锁有什么缺点吗?当然有了,不然 JDK 里为什么出现那么多各式各样的锁,就是因为每一种锁都有其优劣势。

图片

​ 使用锁就需要获得锁、释放锁,CPU 需要通过上下文切换和调度管理来进行这个操作,对于一个 独占锁 而言一个线程在持有锁后没执行结束其他的哥们就必须在外面等着,等到前面的哥们执行完毕 CPU 大哥就会把锁拿出来其他的线程来抢了(非公平)。锁的这种概念基于一种悲观机制,它总是认为数据会被修改,所以你在操作一部分代码块之前先加一把锁,操作完毕后再释放,这样就安全了。其实在 JDK1.5 使用 synchronized 就可以做到 。

图片

​ 但是像上面的操作在多线程下会让 CPU 不断的切换,非常消耗资源,我们知道可以使用具体的某一类锁来避免部分问题。那除了锁的方式还有其他的吗?当然,有人就提出了无锁算法,比较有名的就是我们今天要说的 CAS(compare and swap),和锁不同的是它是一种乐观的机制,它认为别人去拿数据的时候不会修改,但是在修改数据的时候去判断一下数据此时的状态,这样的话 CPU 不会切换,在读多的情况下性能将得到大幅提升。当前我们使用的大部分 CPU 都有 CAS 指令了,从硬件层面支持无锁,这样开发的时候去调用就可以了。不论是锁还是无锁都有其优劣势。

二、CAS

1、CAS 的概述

​ CAS (Compare And Swap,比较与交换),是一种支持硬件层次的原子性操作的经典无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功为止。

CAS算法涉及到三个操作数:

  1. 需要读写的内存位置(V)

  2. 进行比较的旧预期值(A)

  3. 准备写入的新值(B)

2、CAS 的原理

CAS的原理,具体修改数据过程如下:

  1. 用CAS操作数据时,将原始值和要修改的值一并传递给方法;
  2. 比较当前内存中的目标变量值与传进去的原始值是否相同?
  3. 如果相同,表示内存中的目标变量值没有被其他线程修改过,可以直接修改内存种的目标变量值;
  4. 如果不同,那么证明内存种的目标变量值已经被其他线程修改过,则修改失败,CAS会做自旋操作,不断循环重试。

3、CAS 会产生并发安全问题吗?

​ 实际应用中这种情况不会发生。例如:Java中的CAS就体现在 sun.misc.Unsafe 类中的各个方法里。

//下面是Unsafe类中的方法
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

​ 可以看到,这些都是native本地方法,调用过程中,JVM会借助C来调用CPU底层指令实现硬件级别的CAS比较和交换。 看出这是一种完全依赖于底层硬件的操作,通过它来实现原子操作,所以并不会带来并发问题。

注意,CAS是一种系统原语,原语属于操作系统用于范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。

三、Java中的CAS

1、代码实例

​ 我们使用java.util.concurrent.atomic.AtomicInteger类中的compareAndSet()方法,此方法的作用是:将原始值与期待值进行比较,如果相等则将原始值设为要修改的新值(让新值成为原始值),并返回true;不相等则修改失败,返回false。

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
   
  public static void main(String[] args) {
   
    AtomicInteger atomicInteger = new AtomicInteger(5); //初始化原子类的值为0
    //将初始值0与预期值5进行比较,如果相等,则将预期值5改为新值2020
    atomicInteger.compareAndSet(5,<
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值