并发 - 原子类与 CAS 原理

news/2026/1/21 16:06:26/文章来源:https://www.cnblogs.com/liushoushou/p/19512372

知识点 11:并发编程 —— 原子类与 CAS 原理

1. 核心理论:什么是原子操作?

在并发编程中,原子操作指的是一个不会被线程调度机制中断的操作。这种操作一旦开始,就一直运行到结束,中间不会有任何上下文切换。我们之前讨论过,count++ 不是一个原子操作,它包含“读-改-写”三个步骤,因此在多线程环境下是不安全的。

为了解决这个问题,除了使用锁(悲观锁)之外,Java 还提供了一种更高效的“无锁”解决方案——原子类

原子类位于 java.util.concurrent.atomic 包下,例如 AtomicInteger, AtomicLong, AtomicBoolean 等。它们通过一种名为 CAS (Compare-And-Swap) 的机制,以一种乐观的方式保证了复合操作的原子性。


2. 深度剖析:悲观锁 vs 乐观锁

在并发控制中,根据对冲突的“态度”不同,我们可以将锁分为两大类:悲观锁和乐观锁。

2.1 悲观锁 (Pessimistic Locking)

  • 核心思想: 非常悲观,它总是假设最坏的情况,即每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
  • 典型实现: Java 中的 synchronized 关键字和 ReentrantLock 等独占锁,都是悲观锁的实现。它们在操作数据之前,会先获取锁,确保在整个操作过程中,只有一个线程能访问数据。
  • 适用场景: 适合写多读少的场景,即冲突发生的概率很高。如果冲突频繁,使用悲观锁可以避免乐观锁大量的重试操作,反而能提高性能。

2.2 乐观锁 (Optimistic Locking)

  • 核心思想: 非常乐观,它总是假设最好的情况,即每次去拿数据的时候都认为别人不会修改。所以它不会上锁,而是在更新的时候会判断一下在此期间别人有没有去更新这个数据。
  • 典型实现: CAS (Compare-And-Swap) 机制就是乐观锁的典型实现。它在更新前,会先比较当前内存中的值与自己之前取到的值是否一致。如果一致,就执行更新;如果不一致,就认为有冲突,然后进行重试(自旋),直到成功为止。
  • 适用场景: 适合读多写少的场景,即冲突发生的概率很低。因为不上锁,省去了锁的开销,可以获得更高的吞吐量。

3. CAS (Compare-And-Swap) 原理

CAS 是实现乐观锁和原子类的核心技术,是现代 CPU 广泛支持的一种原子指令

  • CAS 指令包含三个操作数

    1. 内存位置 V (要更新的变量的内存地址)
    2. 预期原值 A (我们认为这个变量现在应该是什么值)
    3. 新值 B (如果变量的值和我们预期的 A 一样,就把它更新成 B)
  • 执行过程: 当执行 CAS 指令时,CPU 会原子地完成以下判断和操作:当且仅当内存位置 V 的值等于预期原值 A 时,CPU 才会将该位置的值更新为新值 B。否则,它什么也不做。无论成功与否,它都会返回操作前的旧值。

AtomicInteger.getAndIncrement() 的工作流程 (即 i++ 的原子版)**:

`AtomicInteger` 能保证复合操作的原子性,其秘诀就在于 **“CAS + 循环重试(自旋)”**。1.  在一个**无限循环**(`do-while` 循环,也常被称为**自旋 (Spinning)**)中进行。
2.  **读取**当前 `AtomicInteger` 的 `value` 值(这是一个 `volatile` 变量),我们称之为 `current`。这个值就是我们的“预期原值 A”。
3.  计算出“新值 B”,即 `current + 1`。
4.  调用 `compareAndSet(current, current + 1)` 方法,这个方法会执行底层的 CAS 原子指令,尝试将内存中的值从 `current` 更新为 `current + 1`。
5.  **检查 CAS 结果**:`compareAndSet` 会返回 `true` 或 `false`。-   如果返回 `true`(成功了),意味着在“读-改-写”的瞬间,没有其他线程修改过这个值。循环结束,操作完成。-   如果返回 `false`(失败了),意味着在我们准备写入时,有其他线程已经抢先修改了值。循环**不会结束**,而是会**回到第 2 步**,重新读取最新的值,然后再次尝试 CAS。这个“失败后重试”的过程就是**自旋**。

3.1 CAS 的潜在问题

  1. ABA 问题:

    • 问题描述: 这是 CAS 的一个经典漏洞。如果一个变量的值从 A 变成了 B,然后又变回了 A。当一个线程执行 CAS 时,它会检查发现当前值是 A,与预期值 A 相符,于是执行更新。但它不知道这个值其实中间被改动过。
    • 解决方案: JUC 包提供了 AtomicStampedReference 类来解决这个问题。它通过为每个值关联一个额外的“版本号”(stamp),CAS 操作不仅要检查值是否相等,还要检查版本号是否相等,从而避免了 ABA 问题。
  2. 自旋时间长,开销大: 其实就是 CAS 的开销问题

    • 问题描述: 如果锁的竞争一直很激烈,会导致线程反复地尝试 CAS 操作但一直失败。这个“自旋”的过程会持续占用 CPU,造成大量的计算资源浪费。
    • 结论: 在高竞争的环境下,synchronized 这种能让线程进入阻塞等待状态的“重量级锁”,其性能表现反而可能会优于 CAS 这种需要不断自旋的乐观锁。

4. 生活中的例子与代码示例

  • 生活比喻: 想象你在拍卖会上竞拍一件物品。

    • 共享变量: 当前的最高出价
    • 你的操作 (increment): 你想在当前最高出价的基础上加 100 元。
    • CAS 流程:
      1. 你看到当前的最高出价是 1000 元(读取预期原值 A)。
      2. 你决定出价 1100 元(计算新值 B)。
      3. 你举牌喊价(执行 CAS)。在喊价的瞬间,拍卖师会原子地做一次判断:
        • 成功: 如果在你喊价之前,最高出价仍然是 1000 元,那么你的出价成功,最高价更新为 1100 元。
        • 失败: 如果在你举牌的瞬间,另一个人(其他线程)已经抢先喊出了 1050 元,那么拍卖师会认为你的出价(基于 1000 元)无效。你必须重新听一下现在的最高价是 1050 元,然后在这个基础上再次出价(自旋重试)。
  • 核心代码示例: 我们用原子类来改造之前的 Counter 实验。

package com.study.concurrency;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;// 使用 AtomicInteger 实现的线程安全的计数器
class AtomicCounter {// 1. 使用 AtomicInteger 作为计数器private AtomicInteger count = new AtomicInteger(0);public void increment() {// 2. getAndIncrement() 方法本身就是原子的,它内部封装了 CAS 循环count.getAndIncrement();}public int getCount() {return count.get();}
}public class AtomicTest {public static void main(String[] args) throws InterruptedException {final AtomicCounter counter = new AtomicCounter();ExecutorService threadPool = Executors.newFixedThreadPool(10);Runnable task = () -> {for (int i = 0; i < 1000; i++) {counter.increment();}};for (int i = 0; i < 10; i++) {threadPool.submit(task);}threadPool.shutdown();while (!threadPool.awaitTermination(1, TimeUnit.SECONDS)) {System.out.println("线程池仍在运行...");}System.out.println("\n所有任务执行完毕。");System.out.println("AtomicCounter 的最终值为: " + counter.getCount());System.out.println("预期值应为: 10000");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1195334.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

并发 - Callable 与 Future

知识点 5.1:并发编程进阶 —— Callable 与 Future 在学习了 Runnable 之后,我们很快会发现它的两个主要局限:run() 方法没有返回值。 run() 方法不能抛出受检异常。为了解决这两个问题,JUC 提供了一对更强大的组合…

麦橘超然性能压测报告:单次生成耗时统计

麦橘超然性能压测报告&#xff1a;单次生成耗时统计 1. 引言&#xff1a;为什么这次压测值得关注 你有没有遇到过这样的情况&#xff1a;满怀期待地输入一段精美的提示词&#xff0c;点击“生成”&#xff0c;然后盯着进度条一动不动&#xff0c;等了快一分钟才出图&#xff…

2026营口市英语雅思培训辅导机构推荐;2026权威出国雅思课程排行榜

基于《2025-2026年中国雅思考试行业白皮书》核心数据,结合营口市站前区、西市区、鲅鱼圈区、老边区、盖州市、大石桥市近三年雅思考生备考反馈(有效样本量1500+),本次开展全面深度测评,聚焦雅思培训选课核心痛点,…

fft npainting lama高阶使用技巧:分层修复与边缘羽化实战案例

fft npainting lama高阶使用技巧&#xff1a;分层修复与边缘羽化实战案例 1. 引言&#xff1a;图像修复不只是“一键去物” 你有没有遇到过这种情况&#xff1a;想从照片里去掉一个碍眼的路人&#xff0c;结果修复完边缘生硬得像被刀切过&#xff1f;或者处理一张复杂背景的广…

企业级通信如何选型?(MCP与OpenAI Function Calling技术对决揭秘)

第一章&#xff1a;企业级通信选型的底层逻辑与技术分野 在构建现代分布式系统时&#xff0c;企业级通信机制的选择直接影响系统的可扩展性、容错能力与维护成本。通信架构不仅涉及数据传输方式&#xff0c;更深层地反映了服务治理理念与技术栈的协同逻辑。 同步与异步通信的本…

OOP 经典对比

知识点 4.5:OOP 经典对比 1. 重写 (Override) vs 重载 (Overload) 这是 Java 多态性中两个非常重要且容易混淆的概念。 什么是重写 (Override)? 重写是指子类可以重新定义从父类继承来的、具有相同方法签名(方法名和…

YOLOv11+BiFPN革新小麦杂质检测技术

Key Points - 本报告的核心发现与结论&#xff08;3-5项&#xff09;&#xff1a;YOLOv11 BiFPN 技术组合具备高精度、实时性与强鲁棒性&#xff0c;是小麦杂质检测系统的理想技术选型&#xff1a;该架构通过双向特征融合机制显著提升小目标&#xff08;如尘土、石子&#xff…

手把手教你实现MCP服务器resources热更新,动态调整不再重启服务

第一章&#xff1a;MCP服务器热更新机制概述 在现代高可用服务架构中&#xff0c;MCP&#xff08;Modular Control Plane&#xff09;服务器作为核心控制组件&#xff0c;其持续稳定运行至关重要。热更新机制允许系统在不中断服务的前提下动态加载新代码或配置&#xff0c;极大…

山石网科各硬件产品Console配置口波特率汇总

SG-6000 E/C/P/Z/ISC Probe/LMS 系列设备提供 1 个符合 RS-232C 异步串行规范的配置口(CON 口)。配置口的属性及描述如下表所示:属性 描述连接器类型 RJ-45端口类型 RS-232C波特率 9600bit/s支持服务 与终端的串口相…

揭秘Dify Iteration节点:如何高效处理复杂列表数据?

第一章&#xff1a;揭秘Dify Iteration节点的核心能力 Dify的Iteration节点是工作流编排中实现循环逻辑的关键组件&#xff0c;允许开发者对一组数据进行逐项处理&#xff0c;显著提升自动化流程的灵活性与可扩展性。通过该节点&#xff0c;用户可以在无需编写额外代码的情况下…

基于51单片机智能手环老人防跌倒报警器GSM短信上报设计套件106(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于51单片机智能手环老人防跌倒报警器GSM短信上报设计套件106(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_相关定制&#xff09;_文章底部可以扫码 51单片机智能老人防跌倒报警器GSM短信上报106产品功能描述&#xff1a; 本系统由STC89C52单片机、ADXL345加速度传…

为什么FSMN VAD总检测失败?参数调优实战教程入门必看

为什么FSMN VAD总检测失败&#xff1f;参数调优实战教程入门必看 你是不是也遇到过这种情况&#xff1a;明明音频里有清晰的说话声&#xff0c;FSMN VAD却一点反应都没有&#xff1f;或者语音被莫名其妙地截断&#xff0c;片段切得支离破碎&#xff1f;别急&#xff0c;这并不…

Live Avatar降本部署方案:单GPU+CPU offload低配环境实操教程

Live Avatar降本部署方案&#xff1a;单GPUCPU offload低配环境实操教程 1. 背景与挑战&#xff1a;为什么80GB显存成硬门槛&#xff1f; Live Avatar是由阿里联合高校开源的一款高质量数字人生成模型&#xff0c;支持从文本、图像和音频输入驱动虚拟人物的口型、表情与动作&…

RTX5060显卡对PyTorch与CUDA适配问题解决方案(解决环境依赖问题AI微调部署前奏)

前言 如果大家的电脑显卡是RTX50系列的话&#xff0c;如果按照正常的部署AI&#xff0c;可能尚未进行调试&#xff0c;就会发现环境的依赖报错一大堆&#xff0c;又或者如下图的UserWarning&#xff0c;之所以会是这样&#xff0c;是因为5060的显卡太新了&#xff0c;以至于Py…

2026锦州市英语雅思培训辅导机构推荐;2026权威出国雅思课程排行榜

基于全国雅思培训行业权威调研、锦州市太和区、古塔区、凌河区多维度考生反馈及第三方教育测评认证,本次围绕雅思培训选课核心需求,结合考试提分规律、优质机构筛选标准、高分技巧传授、性价比适配等关键维度,开展深…

强化学习十年演进

结论&#xff1a;未来十年&#xff08;2025–2035&#xff09;&#xff0c;强化学习将从“样本密集的实验室算法”演进为“多模态、能效优先与社会协同的工程化技术栈”&#xff0c;在北京的机器人与自动驾驶落地应优先关注多模态感知RL、节能&#xff08;Green&#xff09;RL …

紧急警告:错误配置导致Claude Desktop丢失MCP Server连接(附修复方案)

第一章&#xff1a;紧急警告&#xff1a;错误配置导致Claude Desktop丢失MCP Server连接 近期多个用户报告&#xff0c;在更新 Claude Desktop 客户端后&#xff0c;应用无法连接至本地运行的 MCP&#xff08;Model Control Plane&#xff09;Server&#xff0c;表现为连接超时…

GEO优化公司推荐哪家好?从技术深度到服务能力的权威解析!

随着生成式搜索与AI问答逐渐成为主流信息入口,企业在“被搜索”之外,开始进入“被理解、被引用、被推荐”的新竞争阶段。由此,GEO正在成为企业数字增长的重要基础设施。面对市场上不断涌现的GEO服务商,企业最关心的…

广东激光熔敷公司怎么选,哪家口碑好?

问题1:广东专业激光熔敷哪家专业?激光熔敷技术在锅炉修复中的核心优势是什么? 在广东的工业防腐防磨领域,广东博盈特焊技术股份有限公司是专业激光熔敷服务的标杆企业。作为2026年深交所创业板上市企业(证券代码:…

Pinterest注册失败怎么办?2026最新解决指南在这里

Pinterest作为全球最大的视觉搜索引擎之一&#xff0c;吸引了无数用户加入。然而&#xff0c;很多用户在注册过程中会遇到各种问题&#xff0c;从账号信息填写不完整&#xff0c;到IP地址被识别为异常&#xff0c;种种障碍常常让人感到沮丧。如果你也在Pinterest注册过程中碰壁…