如何利用 CAS 实现原子操作:深入浅出原子类与线程安全

在并发编程中,确保线程安全是一个重要话题。为了避免多个线程对同一数据进行竞争访问,Java 提供了原子类(Atomic Classes)来保证并发场景下的线程安全,而原子类最核心的实现机制就是 CAS(Compare And Swap) 操作。本文将详细解析原子类如何利用 CAS 实现线程安全,并且带你走进底层实现。

一、原子类与锁的比较

原子类和锁在并发编程中有着相似的作用:它们都能保证多个线程之间访问共享资源时的线程安全。然而,原子类相比锁有明显的优势:

  • 粒度更细:原子类的粒度通常是变量级别的,而锁的粒度一般较大,可能会锁住多个变量,甚至整个方法或代码块。
  • 效率更高:原子类的效率通常高于锁机制,尤其是在低竞争场景下。因为原子类操作通过 CAS 完成,不需要阻塞线程,避免了上下文切换的开销。

二、Java中的六类原子类

Java 提供了多种原子类,常见的有以下几类:

  1. Atomic 基本类型原子类*

    • AtomicIntegerAtomicLongAtomicBoolean
  2. Atomic*Array 数组类型原子类

    • AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray
  3. Atomic*Reference 引用类型原子类

    • AtomicReferenceAtomicStampedReferenceAtomicMarkableReference
  4. Atomic*FieldUpdater 升级类型原子类

    • AtomicIntegerFieldUpdaterAtomicLongFieldUpdaterAtomicReferenceFieldUpdater
  5. Adder 累加器

    • LongAdderDoubleAdder
  6. Accumulator 积累器

    • LongAccumulatorDoubleAccumulator

三、AtomicInteger: 最典型的基本类型原子类

我们以 AtomicInteger 为例来解释原子类的使用。AtomicIntegerint 类型的封装,能够在并发场景下安全地对 int 类型的变量进行原子性操作。

AtomicInteger 常用方法

  • get():获取当前值。
  • getAndSet(int newValue):获取当前值并设置新的值。
  • getAndIncrement():获取当前值并自增。
  • getAndDecrement():获取当前值并自减。
  • getAndAdd(int delta):获取当前值并加上指定值。
  • compareAndSet(int expect, int update):如果当前值等于预期值,则以原子方式更新为新值。

四、如何利用 CAS 实现原子操作?

CAS(Compare And Swap)是原子操作的基础,它通过比较并交换的方式保证线程安全。我们以 AtomicInteger 中的 getAndAdd(int delta) 方法为例来说明 CAS 的底层实现。

getAndAdd 方法实现

public final int getAndAdd(int delta) {return unsafe.getAndAddInt(this, valueOffset, delta);
}

该方法通过调用 Unsafe.getAndAddInt() 实现原子操作,使用 Unsafe 类来操作内存数据。Unsafe 是 Java 提供的一个类,能够直接操作内存,因此它是 CAS 操作的核心。

Unsafe 类与内存操作

Unsafe 类通过本地方法(native methods)提供了底层硬件级别的原子操作,使得 Java 可以通过 unsafe 实现高效的原子操作,而无需使用锁。我们来详细看看 AtomicInteger 如何使用 Unsafe 类来进行 CAS 操作。

public class AtomicInteger {private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) {throw new Error(ex);}}private volatile int value;public final int get() {return value;}// 其他方法...
}

AtomicIntegervalue 变量是 volatile 修饰的,确保线程可见性。valueOffset 是通过 unsafe.objectFieldOffset() 方法获取的 value 字段的内存偏移量,它代表 value 在内存中的位置。

getAndAddInt 方法的实现

getAndAddInt 方法通过循环加上 CAS 来实现原子更新:

public final int getAndAddInt(Object object, long valueOffset, int delta) {int expectedValue;do {expectedValue = this.getIntVolatile(object, valueOffset);} while (!this.compareAndSwapInt(object, valueOffset, expectedValue, expectedValue + delta));return expectedValue;
}

关键步骤解释:

  • expectedValue:首先获取当前 value 的值。
  • compareAndSwapInt:如果当前值与预期值相等,则将 value 更新为 expectedValue + delta
  • 如果更新失败(例如其他线程修改了 value),则重新获取最新的值,再次尝试更新,直到成功。

这个过程通过循环加 CAS 的方式确保了原子性,避免了线程间的冲突。

五、CAS的成功与失败

CAS 操作可能失败。失败的原因是多个线程竞争更新同一数据时,可能会出现“脏读”现象。比如,一个线程 A 读取了值 X,线程 B 在此过程中修改了值 X。当线程 A 尝试通过 CAS 更新值时,操作会失败,并重新获取值进行重试。

这种机制虽然能保证线程安全,但也会带来一些性能问题,特别是在高度竞争的情况下,CAS 可能会导致“活锁”现象,影响效率。

六、总结

通过原子类和 CAS,我们能够在并发环境下实现高效的线程安全操作。与锁机制相比,CAS 通过避免线程阻塞,通常能够提供更高的性能。理解 CAS 的底层原理,掌握如何使用原子类,是每个并发编程开发者必备的技能。

如果你对原子操作和并发编程有更多的兴趣,欢迎关注我的 CSDN 博客,我们将继续深入讨论并发编程中的高级技术与优化技巧!

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

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

相关文章

四万字长文SpringBoot、Spring、SpringMVC等相关面试题(注:该篇博客将会持续维护 最新维护时间:2024年11月12日)

🧸本篇博客重在讲解SpringBoot、Spring、SpringMVC等相关面试题,将会实时更新,欢迎大家添加作者文末联系方式交流 📜JAVA面试题专栏:JAVA崭新面试题——2024版_dream_ready的博客-CSDN博客 📜作者首页&…

02_ElementUI

一.前端工程化 1.1 概述 前端工程化是使用软件工程的方法来单独解决前端的开发流程 中模块化、组件化、规范化、自动化的问题,其主要目的为了 提高效率和降低成本。 1.2 NodeJS的安装 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环 境,可以使 JavaS…

三、运算符、数据类型转换(显式、隐式)、语句(if、三元、switch、while、for)

1. 运算符 1.1 自增自减 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> &…

数据安全、信息安全、网络安全区别与联系

关键字&#xff1a; 信息安全 数据安全 网络安全 [导读] 在 “互联网 ” 被广泛提及的今天&#xff0c;安全问题也越来越多的受到人们关注&#xff0c;然而很多人对于 “信息安全”、“数据安全”、“网络安全” 的概念并不是很清楚。我们汇总了官方机构给这三者的定义&#…

基于单片机的多功能视力保护器设计(论文+源码)

1. 功能设计 本次课题为多功能视力保护器&#xff0c;具体设计功能如下&#xff1a; (1)当使用者的眼睛距离写字台低于25cm时&#xff0c;报警灯闪烁以提醒使用者及时调整坐姿。 (2)学习环境光线自动检测&#xff1a;当光照强度低于1001X时&#xff0c;语音提醒使用者调整光…

关于sass在Vue3中编写bem框架报错以及警告问题记录

在编写完bem框架后 在vite.config.ts文件进行预编译处理时&#xff0c;报错的错误 1. 处理方式&#xff1a;使用新版api&#xff0c; 如图&#xff1a; 2. 处理方式&#xff1a;使用 use 替换掉 import&#xff0c; 如图&#xff1a; 3. 处理方式&#xff1a;使用路径别名&am…

【 AI写作鹅-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

什么是 eCPRI,它对 5G 和 Open RAN 有何贡献?

这里写目录标题 eCPRI 协议平面&#xff1a;功能分解eCPRI与CPRI的区别CPRI具有以下特点&#xff1a;eCPRI具有以下特点&#xff1a;eCPRI 的优势 所需带宽减少 10 倍适用于 5G 和 Open RAN 的 eCPRI&#xff1a; 通用公共无线接口&#xff08;CPRI&#xff09;是一种行业合作&…

《硬件架构的艺术》笔记(二):时钟与复位

本章主要针对ASIC设计给出建议&#xff0c;独立于CAD工具以及工艺&#xff0c;主要针对模块设计和存储器接口。 同步设计 这是对时钟域控制最安全的方法&#xff0c;单个主时钟和单个主置位/复位信号驱动设计中所有时序器件。 避免使用行波计数器 行波计数器&#xff1a;用触…

使用@react-three/fiber,@mkkellogg/gaussian-splats-3d加载.splat,.ply,.ksplat文件

前言 假设您正在现有项目中集成这些包&#xff0c;而该项目的构建工具为 Webpack 或 Vite。同时&#xff0c;您对 Three.js 和 React 有一定的了解。如果您发现有任何错误或有更好的方法&#xff0c;请随时留言。 安装 npm install three types/three react-three/fiber rea…

「QT」几何数据类 之 QVector2D 二维向量类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

NVIDIA RTX 系统上使用 llama.cpp 加速 LLM

NVIDIA RTX 系统上使用 llama.cpp 加速 LLM 文章目录 NVIDIA RTX 系统上使用 llama.cpp 加速 LLMllama.cpp 概述llama.cpp 在 NVIDIA RTX 上的加速性能使用 llama.cpp 构建的开发人员生态系统使用 llama.cpp 在 RTX 平台上加速的应用程序开始使用 适用于 Windows PC 的 NVIDIA …

[CKS] K8S NetworkPolicy Set Up

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于不安全项目修复的题目。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] K8S Ne…

Odoo:免费开源的流程制造行业ERP管理系统

概述 聚焦流程制造连续性生产的特性&#xff0c;提供集成PLMERPMESBI的一体化解决方案&#xff0c;涵盖计划、生产、质量、配方、供销、库存、成本、设备、资金管理等业务领域的整体性解决方案 行业的最新洞察&行业典型痛点 一、生产过程需要精细化控制 需要在各种制约…

MySQL技巧之跨服务器数据查询:基础篇-动态参数

MySQL技巧之跨服务器数据查询&#xff1a;基础篇-动态参数 上一篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的连接名: MY_ODBC_MYSQL 以及用同样的方法&a…

【Python爬虫实战】轻量级爬虫利器:DrissionPage之SessionPage与WebPage模块详解

&#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 目录 前言 一、SessionPage &#xff08;一&#xff09;SessionPage 模块的基本功能 &#xff08;二&#xff09;基本使…

vue3使用VueQuill插入自定义按钮

在 Vue 3 项目中使用 VueQuill 编辑器时&#xff0c;我们可以自定义内容来满足特定的需求。本文将介绍如何在 VueQuill 中插入自定义内容&#xff0c;比如插入特定的标签或样式元素。 Quill官方中文文档 1. 项目设置和依赖安装 如果你还没有创建 Vue 3 项目&#xff0c;可以…

OpenHamrony4.0去除锁屏是一种什么体验?触觉智能给你支支招

本文介绍在开源鸿蒙OpenHarmony 4.0系统下&#xff0c;去除锁屏开机后直接进入界面的方法&#xff0c;触觉智能Purple Pi OH鸿蒙开发板演示&#xff0c;搭载了瑞芯微RK3566芯片&#xff0c;类树莓派设计&#xff0c;Laval官方社区主荐&#xff0c;已适配全新OpenHarmony5.0 Rel…

【bat】自动生成指定层级文件夹

&#x1f305; 一日之计在于晨&#xff0c;启航新程 ⭐ 本期特辑&#xff1a;自动生成指定层级文件夹 &#x1f3c6; 系列专题&#xff1a;BAT脚本工坊 文章目录 前言批处理脚本介绍脚本执行过程总结 前言 在日常的计算机使用过程中&#xff0c;我们经常需要创建文件夹来组织和…

基于yolov5的番茄成熟度检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; yolov5 番茄成熟度检测系统&#xff0c;支持图像、视频和摄像实时检测【pytorch框架、python源码】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于 YOLOv5 的番茄成熟度检测系统是在 PyT…