【高薪程序员必看】万字长文拆解Java并发编程!(6-1):从CAS无锁机制到Atomic原子类实战指南

简介: 🌟 ​🌟今天给大家带来的是 ​💻⚡在这篇文章中,我们将一起探索:🔹 ​的底层原理,它是如何通过 ​实现无锁并发的?🔹 ​的终极对决,为什么高并发场景下CAS性能更优?🔹 ​的陷阱与解决方案——和实战演示!🔹 ​​(LongAdder等)的使用场景与性能对比🔹 危险的 ​黑魔法:为什么阿里禁止使用却又是并发库的基石?无论你是:✅ ​​(BATJ高频考点)✅ ​​(如何设计百万级计数器)✅ ​​(从Java代码到CPU指令的全链路分析)这篇文章都会让你收获满满!✨。

  image.gif 编辑

🌟 大家好,我是摘星! 🌟

今天给大家带来的是 《Java高并发编程核心:CAS无锁机制与原子类深度解析》 💻⚡

在这篇文章中,我们将一起探索:

🔹 CAS(Compare-And-Swap) 的底层原理,它是如何通过 CPU指令 实现无锁并发的?

🔹 乐观锁 vs 悲观锁 的终极对决,为什么高并发场景下CAS性能更优?

🔹 ABA问题 的陷阱与解决方案——AtomicStampedReferenceAtomicMarkableReference实战演示!

🔹 Atomic原子类全家桶AtomicIntegerLongAdder等)的使用场景与性能对比

🔹 危险的 Unsafe 黑魔法:为什么阿里禁止使用却又是并发库的基石?

无论你是:

面试突击(BATJ高频考点)

性能调优(如何设计百万级计数器)

底层原理控(从Java代码到CPU指令的全链路分析)

这篇文章都会让你收获满满!✨

你在项目中用过CAS吗?遇到过哪些坑?欢迎评论区分享~ 👇

目录

6. 无锁并发-乐观锁

6.1. CAS

6.2. ABA问题解决

6.3. 原子类


6. 无锁并发-乐观锁

6.1. CAS

CAS(Compare and Swap)是一种无锁的并发控制机制,常用于多线程环境下的原子操作。

CAS操作包含三个参数:变量当前值、变量期望值、更新值,具体步骤如下:

  1. 读取变量当前值
  2. 比较变量当前值和期望值是否相等
  3. 如果相等,说明变量的值没有被其他线程修改过,将更新值赋给变量
  4. 如果不相等,说明变量的值已经被其他线程修改,CAS操作失败

要素

说明

操作原理

比较当前值(V)、期望值(E)、新值(N),若 V==E 则更新为 N,否则失败

底层依赖

volatile(保证可见性) + CPU原子指令(如x86的CMPXCHG

乐观锁思想

假设无竞争,失败时重试而非阻塞

CAS操作依赖于volatile的可见性来读取变量当前值,并且依赖volatile的禁止重排序的特性来保证原子性

CAS是基于乐观锁的思想,假设别的线程不会修改共享资源,就算修改了也没关系,乐观锁在修改共享资源时会对资源进行一次检查,如果没有被修改过则直接更新,如果被修改过就重试。因此效率高,因为它避免了加锁和解锁的操作,竞争失败时也不会发生线程上下文切换的情况。但是它也存在一些问题,比如ABA问题,以及激烈的竞争情况下会导致不断重试。

在Java中,CAS是使用java.util.concurrent.atomic包中的原子类实现的,常用的CAS操作是由AtomicXXX类提供的,比如AtomicIntegerAtomicLong等。这些类提供了一系列的原子操作方法,如compareAndSet()getAndIncrement()等,来实现无锁的并发控制。

对比维度

CAS(乐观锁)

悲观锁(如synchronized)

线程阻塞

❌ 无阻塞,失败时自旋重试

✅ 竞争失败时线程挂起

适用场景

低冲突、短耗时操作(如计数器)

高冲突、长耗时操作(如数据库事务)

ABA问题

存在(需版本号解决)

不存在

性能开销

⚡ 轻量级(无上下文切换)

⚠️ 重量级(锁竞争、唤醒开销)

6.2. ABA问题解决

CAS 存在一个经典的问题,就是 ABA 问题,即在多线程环境下,如果一个值原来是 A,后来变成了 B,然后又变回 A,但是CAS操作仍然操作成功,这是不被允许的。

为了解决 CAS 的 ABA 问题,Java 并发包提供了以下两种方法:

  1. 使用 AtomicStampedReferenceAtomicStampedReference 是一个带有标记的引用类,它对应的共享变量是一个包装了 value 和 stamp(标记)的对象。通过比较和交换引用值和标记值,AtomicStampedReference 可以解决 ABA 问题。每当共享变量发生变化时,都需要更新标记值,这样即使值发生了 ABA 的变化,标记值也会发生变化,从而保证 CAS 可以正确地判断出是否发生了变化。
  2. 使用 AtomicMarkableReferenceAtomicMarkableReference 是另一个带有标记的引用类,相比于 AtomicStampedReference,它使用了一个 boolean 类型的标记来解决 ABA 问题。与 AtomicStampedReference 类似,每当共享变量发生变化时,都需要更新标记值。通过比较和交换引用值和标记值,AtomicMarkableReference 可以避免 ABA 问题。

方案

原理

代码示例

AtomicStampedReference

通过int stamp版本号标记状态变化

java<br>AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);<br>ref.compareAndSet(100, 200, 0, 1);<br>

AtomicMarkableReference

通过boolean mark标记状态(简化版)

java<br>AtomicMarkableReference<Integer> ref = new AtomicMarkableReference<>(100, false);<br>ref.compareAndSet(100, 200, false, true);<br>

6.3. 原子类

在Java并发编程中,原子类是一组提供原子操作的类。原子操作是指不可分割的操作,不会被其他线程中断,也不会被中断其他操作。Java提供了一些原子类,用于处理并发编程中的线程安全问题。

以下是一些常见的原子类:

  1. AtomicBoolean:提供了用于原子操作布尔值的方法,比如get()、set()、getAndSet()和compareAndSet()等。
  2. AtomicInteger和AtomicLong:分别提供了原子操作整型和长整型的方法。例如,incrementAndGet()、decrementAndGet()、getAndIncrement()、getAndDecrement()、getAndAdd()等。
  3. AtomicReference:用于原子操作引用类型的变量。它提供了get()、set()、getAndSet()和compareAndSet()等方法。
  4. AtomicReferenceArray:类似于AtomicReference,但是用于数组。它提供了对数组元素进行原子操作的方法,如get()、set()、getAndSet()和compareAndSet()等。
  5. AtomicIntegerArray和AtomicLongArray:类似于AtomicInteger和AtomicLong,但是用于整型数组和长整型数组。提供了对数组元素进行原子操作的方法,如get()、set()、getAndSet()和compareAndSet()等。

类别

典型类

适用场景

基本类型

AtomicInteger/Long

计数器、序号生成(如i++原子化)

引用类型

AtomicReference

对象引用的原子更新(如单例模式)

数组类型

AtomicIntegerArray

并发安全的数组操作

字段更新器

AtomicIntegerFieldUpdater

已存在类的volatile字段原子更新(减少对象开销)

AtomicInteger API

方法

作用

等效代码(非原子)

i.get()

获取当前值

int val = i;

i.incrementAndGet()

++i(先增后取)

return ++i;

i.getAndIncrement()

i++(先取后增)

return i++;

i.updateAndGet(x -> x*2)

原子运算(如乘2)

i = i * 2; return i;

🌟 感谢大家看到这里!我是摘星,我们下期再见! 🌟


🔹 如果这篇文章对你有帮助,欢迎点赞❤️ + 收藏⭐,让更多小伙伴看到~

🔹 有任何问题或想法,欢迎在评论区留言,我会一一回复!

🔹 关注我,解锁更多 Java 高并发 | 分布式 | JVM 调优 的深度解析!

相关文章
|
人工智能 Kubernetes Java
回归开源,两位 Java 和 Go 程序员分享的开源贡献指引
Higress是一个基于Istio和Envoy的云原生API网关,支持AI功能扩展。它通过Go/Rust/JS编写的Wasm插件提供可扩展架构,并包含Node和Java的console模块。Higress起源于阿里巴巴,解决了Tengine配置重载及gRPC/Dubbo负载均衡问题,现已成为阿里云API网关的基础。本文介绍Higress的基本架构、功能(如AI网关、API管理、Ingress流量网关等)、部署方式以及如何参与开源贡献。此外,还提供了有效的开源贡献指南和社区交流信息。
2528 33
|
人工智能 Cloud Native Java
2025 年 Java 应届生斩获高薪需掌握的技术实操指南与实战要点解析
本指南为2025年Java应届生打造,涵盖JVM调优、响应式编程、云原生、微服务、实时计算与AI部署等前沿技术,结合电商、数据处理等真实场景,提供可落地的技术实操方案,助力掌握高薪开发技能。
546 2
|
Java 程序员 应用服务中间件
【高薪程序员必看】万字长文拆解Java并发编程!(2 2-2)
📌 核心痛点暴击:1️⃣ 面了8家都被问synchronized锁升级?一张图看懂偏向锁→重量级锁全过程!2️⃣ 线程池参数不会配?高并发场景下这些参数调优救了项目组命!3️⃣ volatile双重检测单例模式到底安不安全?99%人踩过的内存可见性大坑!💡 独家亮点抢先看:✅ 图解JVM内存模型(JMM)三大特性,看完再也不怕指令重排序✅ 手撕ReentrantLock源码,AQS队列同步器实现原理大揭秘✅ 全网最细线程状态转换图(附6种状态转换触发条件表)
311 0
|
网络协议 Java 大数据
【高薪程序员必看】万字长文拆解Java并发编程!(1)
📌 核心痛点暴击:1️⃣ 面了8家都被问synchronized锁升级?一张图看懂偏向锁→重量级锁全过程!2️⃣ 线程池参数不会配?高并发场景下这些参数调优救了项目组命!3️⃣ volatile双重检测单例模式到底安不安全?99%人踩过的内存可见性大坑!💡 独家亮点抢先看:✅ 图解JVM内存模型(JMM)三大特性,看完再也不怕指令重排序✅ 手撕ReentrantLock源码,AQS队列同步器实现原理大揭秘✅ 全网最细线程状态转换图(附6种状态转换触发条件表)
235 0
|
安全 Java 程序员
【高薪程序员必看】万字长文拆解Java并发编程!(2 2-1)
🔥【高薪程序员必看】万字长文拆解Java并发编程!面试官看了直呼内行,90%人不知道的线程安全骚操作!💻🚀《16个高频面试灵魂拷问+底层源码暴击》🔥👉戳这里看如何用1个月经验吊打3年程序员!📌 核心痛点暴击:1️⃣ 面了8家都被问synchronized锁升级?一张图看懂偏向锁→重量级锁全过程!2️⃣ 线程池参数不会配?高并发场景下这些参数调优救了项目组命!3️⃣ volatile双重检测单例模式到底安不安全?99%人踩过的内存可见性大坑!
211 0
|
缓存 安全 Java
【高薪程序员必看】万字长文拆解Java并发编程!(3-1):并发共享问题的解决与分析
活锁:多个线程相互影响对方退出同步代码块的条件而导致线程一直运行的情况。例如,线程1的退出条件是count=5,而线程2和线程3在其代码块中不断地是count进行自增自减的操作,导致线程1永远运行。内存一致性问题:由于JIT即时编译器对缓存的优化和指令重排等造成的内存可见性和有序性问题,可以通过synchronized,volatile,并发集合类等机制来解决。这里的线程安全是指,多个线程调用它们同一个实例的方法时,是线程安全的,但仅仅能保证当前调用的方法是线程安全的,不同方法之间是线程不安全的。
261 0
|
Java 程序员
【高薪程序员必看】万字长文拆解Java并发编程!(3-2):并发共享问题的解决与分析
wait方法和notify方法都是Object类的方法:让当前获取锁的线程进入waiting状态,并进入waitlist队列:让当前获取锁的线程进入waiting状态,并进入waitlist队列,等待n秒后自动唤醒:在waitlist队列中挑一个线程唤醒:唤醒所有在waitlist队列中的线程它们都是之间协作的手段,只有拥有对象锁的线程才能调用这些方法,否则会出现IllegalMonitorStateException异常park方法和unpark方法是LockSupport类中的方法。
265 0
|
存储 安全 Java
【高薪程序员必看】万字长文拆解Java并发编程!(4-1):悲观锁底层原理与性能优化实战
目录4. JVM字节码文件4.1. 字节码文件-组成4.1.1. 组成-基础信息4.1.1.1. 基础信息-魔数4.1.1.2. 基础信息-主副版本号4.1.2. 组成-常量池4.1.3. 组成-方法4.1.3.1. 方法-工作流程4.1.4. 组成-字段4.1.5. 组成-属性4.2. 字节码文件-查看工具4.2.1. javap4.2.2. jclasslib4.2.3. 阿里Arthas
258 0
|
Java 程序员
java程序员,如何坚持学习下去?
java程序员,如何坚持学习下去?
273 1
|
Kubernetes 安全 Java
Java程序员2021年应该学习的11项技能
Java程序员2021年应该学习的11项技能
353 0
Java程序员2021年应该学习的11项技能