Java并发基础:原子类之AtomicIntegerFieldUpdater全面解析
本文概要
AtomicIntegerFieldUpdater
类提供了一种高效、简洁的方式来原子性地更新对象的volatile字段,无需使用重量级的锁机制,它通过基于反射的API实现了细粒度的并发控制,提升了多线程环境下的性能表现。
AtomicIntegerFieldUpdater核心概念
AtomicIntegerFieldUpdater
类是一个用于原子更新字段值的工具类,它特别适用于在并发环境中,当多个线程需要访问和修改某个对象的某个volatile
整型字段时,能够保证该字段更新的原子性。
模拟一个业务场景,假设有一个在线书店,每个书籍都有一个库存数量字段,表示为int stockCount
,当多个用户同时购买同一本书时,系统需要确保库存数量的减少是线程安全的,即不会出现超卖的情况。
在传统的同步方法中,可能会使用synchronized
关键字或ReentrantLock
来同步整个库存减少的方法,但这样做的话,每次只有一个线程能够执行减少库存的操作,其他线程必须等待,这在高并发环境下可能会导致性能瓶颈。
在这个场景中使用AtomicIntegerFieldUpdater
类的decrementAndGet
方法,这个方法会以原子方式将库存数量减1,并返回更新后的值,同时它是以原子地更新库存数量字段,而不需要对整个方法进行同步,多个线程可以同时尝试减少库存,但每次只有一个线程能够成功更新库存数量,其他线程会重新尝试,直到成功为止。
注意:使用AtomicIntegerFieldUpdater
类时,库存数量字段必须是volatile
修饰的,这样可以保证所有线程都能看到最新的值,同时由于AtomicIntegerFieldUpdater
类是基于反射实现的,因此,它只能更新公共字段或具有公共setter方法的字段。
AtomicIntegerFieldUpdater使用案例
下面是一个简单的Java代码案例,演示了如何使用AtomicIntegerFieldUpdater
类,如下代码:
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; public class AtomicIntegerFieldUpdaterExample { // 定义一个包含volatile字段的类 static class MyObject { volatile value = 0; // 这个字段将被原子更新 } // 创建一个AtomicIntegerFieldUpdater实例,用于更新MyObject的value字段 private static final AtomicIntegerFieldUpdater<MyObject> updater = AtomicIntegerFieldUpdater.newUpdater(MyObject.class, "value"); public static void main(String[] args) { // 创建一个MyObject实例 MyObject myObject = new MyObject(); // 输出初始值 System.out.println("Initial value: " + myObject.value); // 使用AtomicIntegerFieldUpdater原子地增加value字段的值 updater.incrementAndGet(myObject); // 输出更新后的值 System.out.println("Value after increment: " + myObject.value); // 使用AtomicIntegerFieldUpdater原子地将value字段的值设置为100 updater.set(myObject, 100); // 输出再次更新后的值 System.out.println("Value after setting to 100: " + myObject.value); }
}
输出将是:
Initial value: 0
Value after increment: 1
Value after setting to 100: 100
代码解释:
- 定义一个名为
MyObject
的静态内部类,该类有一个volatile
字段value
。 - 创建一个
AtomicIntegerFieldUpdater
类的实例updater
,该实例将用于原子地更新MyObject
类的value
字段。 - 在
main
方法中,创建了MyObject
的实例,并使用updater
原子地增加和设置value
字段的值。 - 使用
System.out.println
来输出value
字段的初始值、增加后的值和设置为100后的值。
AtomicIntegerFieldUpdater核心API
AtomicIntegerFieldUpdater
类是Java的java.util.concurrent.atomic
包中的一个工具类,这个类的主要是用于原子地更新指定对象的指定volatile
字段,以下是该类中一些主要方法的含义:
newUpdater(Class<T> tclass, String fieldName)
:
这是一个静态方法,用于创建一个新的AtomicIntegerFieldUpdater
,它能够以原子方式更新给定类的指定名称的volatile
字段,tclass
是字段所在类的Class
对象,fieldName
是要更新的字段的名称。get(T obj)
:
这个方法获取指定对象的volatile
字段的当前值,obj
是包含要获取字段的对象。set(T obj, int newValue)
:
这个方法以原子方式设置指定对象的volatile
字段的值为newValue
,obj
是包含要设置字段的对象,newValue
是要设置的新值。lazySet(T obj, int newValue)
:
这个方法最终将设置指定对象的volatile
字段的值为newValue
,但它允许之后的内存操作重排序,也就是说这个操作可能不是立即对其他线程可见的,它通常用于提高性能,但牺牲了一些一致性保证。getAndSet(T obj, int newValue)
:
这个方法以原子方式设置指定对象的volatile
字段的值为newValue
,并返回该字段的旧值,obj
是包含要设置字段的对象,newValue
是要设置的新值。getAndAdd(T obj, int delta)
:
这个方法以原子方式将给定值delta
添加到指定对象的volatile
字段的当前值,并返回更新前的值,obj
是包含要添加字段的对象,delta
是要添加的值。incrementAndGet(T obj)
:
这个方法以原子方式将指定对象的volatile
字段的当前值增加1,并返回更新后的值,obj
是包含要增加字段的对象。decrementAndGet(T obj)
:
这个方法以原子方式将指定对象的volatile
字段的当前值减少1,并返回更新后的值,obj
是包含要减少字段的对象。addAndGet(T obj, int delta)
:
这个方法以原子方式将给定值delta
添加到指定对象的volatile
字段的当前值,并返回更新后的值,obj
是包含要添加字段的对象,delta
是要添加的值。compareAndSet(T obj, int expect, int update)
:
这个方法以原子方式将指定对象的volatile
字段的值与expect
值进行比较,如果当前值等于expect
值,则使用update
值更新该字段,如果更新成功,则返回true
,否则返回false
,这个方法通常用于实现基于比较的同步机制,如自旋锁。
使用AtomicIntegerFieldUpdater
时,必须确保被更新的字段是volatile
修饰的,并且对于使用AtomicIntegerFieldUpdater
的类是可访问的(即字段是public
的,或者与AtomicIntegerFieldUpdater
在同一个包中且字段是包私有的,或者通过其他方式使字段可访问),此外,字段也不能是static
的。
AtomicIntegerFieldUpdater技术原理
AtomicIntegerFieldUpdater
类用于对对象的某个volatile
字段进行原子性更新,该类的实现原理基于Java的内存模型(JMM)和Unsafe类的底层操作。
实现原理
- Java内存模型(JMM):使用Java内存模型保证了多线程之间变量的可见性和原子性操作,使用
volatile
关键字确保了一个线程对变量的修改对其他线程是立即可见的,并且禁止了指令重排。 - Unsafe类:
AtomicIntegerFieldUpdater
的底层实现依赖于sun.misc.Unsafe
类,该类提供了低级别的、非安全的、操作系统级别的访问方法,它可以直接访问内存、创建对象、数组等,而不受Java访问控制的限制。 - 反射:
AtomicIntegerFieldUpdater
使用反射来获取要更新的字段的Field
对象,然后通过Unsafe
类直接操作这个字段的内存地址。 - 原子操作:
Unsafe
类提供了一系列原子操作方法,如compareAndSwapInt
,这是一个基于硬件支持的原子比较并交换(CAS)操作,CAS操作包括三个参数:一个内存位置(V)、预期原值(A)和新值(B),如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置的值更新为新值B,否则,处理器不做任何操作,无论哪种情况,它都会在CAS指令之前返回该位置的值,这一过程是原子的,也就是说在执行过程中不会被其他线程打断。
底层算法
AtomicIntegerFieldUpdater
的底层算法主要基于CAS操作来实现原子性更新,以incrementAndGet
方法为例:
- 使用一个
do-while
循环来尝试更新字段的值。 - 在循环体内,首先使用
Unsafe
类的getIntVolatile
方法获取当前字段的值。 - 计算新的值(当前值 + 1)。
- 使用
Unsafe
类的compareAndSwapInt
方法尝试将字段的值从当前值更新为新值,如果成功,则退出循环并返回新值;如果失败(说明其他线程已经修改了该字段的值),则继续循环。
这种基于CAS的算法是一种无锁算法,也称为乐观锁算法,它不需要获取和释放锁,而是通过不断重试来确保更新的原子性,在高并发环境下,这种算法通常比传统的基于锁的算法具有更好的性能。
学习总结
AtomicIntegerFieldUpdater
类允许以原子方式更新对象的某个volatile
字段,而无需使用synchronized
关键字,这样做的优点在于减少了锁的竞争,提升了多线程环境下的性能,并且使用简单,只需通过反射指定字段即可。
但是,由于使用了反射,所以字段必须是可访问的,这可能会破坏封装性,并且,它只能更新volatile
类型的字段,对于其他类型的字段或者非volatile
字段则无能为力。
在使用AtomicIntegerFieldUpdater
时,建议仅在确实需要原子性更新且性能是关键因素时使用,并且要要注意保持字段的可访问性,并确保字段是volatile
类型的。
END!
END!
END!
往期回顾
精品文章
Java并发基础:concurrent Flow API全面解析
Java并发基础:CopyOnWriteArraySet全面解析
Java并发基础:ConcurrentSkipListMap全面解析
Java并发基础:ConcurrentSkipListSet全面解析!
Java并发基础:SynchronousQueue全面解析!
相关文章:

Java并发基础:原子类之AtomicIntegerFieldUpdater全面解析
本文概要 AtomicIntegerFieldUpdater类提供了一种高效、简洁的方式来原子性地更新对象的volatile字段,无需使用重量级的锁机制,它通过基于反射的API实现了细粒度的并发控制,提升了多线程环境下的性能表现。 AtomicIntegerFieldUpdater核心概…...

普中51单片机学习(串口通信)
串口通信 原理 计算机通信是将计算机技术和通信技术的相结合,完成计算机与外部设备或计算机与计算机之间的信息交换 。可以分为两大类:并行通信与串行通信。并行通信通常是将数据字节的各位用多条数据线同时进行传送 。控制简单、传输速度快࿱…...

【ArcGIS】利用高程进行坡度分析
在ArcGIS中利用高程进行坡度分析 坡度ArcGIS实操参考 坡度 坡度是地表单元陡缓的程度,通常把坡面的垂直高度和水平距离的比值称为坡度。 坡度的表示方法有百分比法、度数法、密位法和分数法四种,其中以百分比法和度数法较为常用。 (1&#…...
递归读取文件夹下的所有文件
水一篇文章 🐶 代码 package file;import org.apache.commons.lang3.StringUtils; import org.junit.Test;import java.io.File; import java.util.Objects;/*** FlattenDirFiles** author allens* date 2024/2/19*/ public class FlattenDirFiles {// 文件数量pri…...
phpspreadsheet导出数据和图片到excel
仅作记录,废话不多说 前提是已经安装了phpspreadsheet ( composer require phpoffice/phpspreadsheet ) 一、 数据拼装,调用excel类 <?php /*** 电子台账* Date: 2023/4/20* Time: 17:28*/namespace app\store\controlle…...
Seata的 TCC 模式
目录 概述 使用 依赖与配置 代码 概述 TCC 模式是一种侵入式的分布式事务解决方案,它不依赖于数据库的事务,而是要求开发者自定义完成 预提交、提交、回滚的方法逻辑。因此,它是一个种偏 复杂、灵活、有侵入性 的分布式事务处理方案。 De…...
Vue全局指令防止重复点击(等待请求)
继《vue之全局请求loading》之后,总觉得全局loading有时候不太…友好,所以总想将loading加到被点击的元素上面,于是乎就想到了点击事件与请求方法相关联,本想重写组件的click方法,但是这样对组件的影响太大,…...

数据库索引面试的相关问题
查看索引的执行计划 索引失效的情况 1、索引列上做了计算,函数,类型转换等操作。索引失效是因为查询过程需要扫描整个索引并回表。代价高于直接全表扫描。 Like匹配使用了前缀匹配符“%abc” 字符串不加引号导致类型转换。 原因: 常见索…...
Spring启动生命周期
Spring Boot 生命周期详解 Spring Boot 应用程序的生命周期包含几个阶段,每个阶段都有特定的事件和钩子,允许开发者在应用程序的不同生命周期阶段插入自定义逻辑。以下是 Spring Boot 生命周期的主要阶段和对应的事件: 准备阶段:…...
瑞芯微RK3568芯片介绍
RK3568简介 RK3568是一款由瑞芯微电子有限公司(Rockchip Electronics Co. Ltd)推出的高性能多媒体处理器,定位于中高端市场,被广泛应用于平板电脑、多媒体盒子、电子看板和工业控制等领域。以下是对这款芯片的简要介绍࿱…...

15.一种坍缩式的简单——组合模式详解
当曾经的孩子们慢慢步入社会才知道,那年味渐淡的春节就像是疾驰在人生路上的暂停键。 它允许你在隆隆的鞭炮声中静下心来,瞻前顾后,怅然若失。 也允许你在寂静的街道上屏气凝神,倾听自己胸腔里的那团人声鼎沸。 孩子们会明白的&am…...

Node.js的debug模块源码分析及在harmonyOS平台移植
Debug库 是一个小巧但功能强大的 JavaScript 调试工具库,可以帮助开发人员更轻松地进行调试,以便更快地发现和修复问题。它的主要特点是可以轻松地添加调试日志语句,同时在不需要调试时可以轻松地禁用它们,以避免在生产环境中对性…...

【Crypto | CTF】BUUCTF RSA2
天命:密码学越来越难了,看别人笔记都不知道写啥 天命:莫慌,虽然我不会推演法,但我可以用归纳法 虽然我不知道解题的推演,但我可以背公式啊哈哈哈 虽然我不会这题,但是我也能做出来 公式我不知…...

单片机学习笔记---红外遥控红外遥控电机调速(完结篇)
目录 低电平触发中断和下降沿触发中断的区别 红外遥控 Int0.c Int.h Timer0.c Timer0.h IR.c IR.h main.c 红外遥控电机调速 Timer1.c Timer.h Motor.c Motor.h main.c 上一节讲了红外发送和接收的工作原理,这一节开始代码演示! 提前说…...

Linux第62步_备份移植好的所有的文件和文件夹
1、备份“my-tfa”目录下所有的文件和文件夹 1)、打开终端 输入“ls回车”,列出当前目录下所有的文件和文件夹 输入“cd linux回车”,切换“linux”目录下 输入“ls回车”,列出当前目录下所有的文件和文件夹 输入“cd atk-mp1/回车”&am…...
【xss跨站漏洞】xss漏洞前置知识点整理
xss漏洞成因 xss漏洞是一种前端javascript产生的漏洞。 我们网站基本都是会用到javascript编写一些东西,浏览器也能直接识别javascript。 如果有一个地方能够输入文字,但是他又没有过滤你的输入,那么自己或者他人看到你输入的javascript代…...
mac下mysql 常用命令
mysql启动命令 在Mac OS X启动和停止MySQL服务的命令, 启动MySQL服务 sudo /usr/local/mysql/support-files/mysql.server start 停止MySQL服务 sudo /usr/local/mysql/support-files/mysql.server stop 重启MySQL服务 sudo /usr/local/mysql/support-files/mys…...
2.21号qt
1.QMainWindow中常用的类 继承于QMainWindow类,原因该类提供了QWidget没有提供的成员函数。 菜单栏、工具栏、状态栏、浮动窗口(铆接部件)、核心部件 1.1 菜单栏 QMenuBar //创建菜单栏 QMenuBar 最多只能有一个 QMenuBar *mbar menu…...
什么是MVVM?MVC、MVP与MVVM模式的区别?
MVVM(Model-View-ViewModel)是一种软件架构模式,用于将用户界面(View)与业务逻辑(Model)分离,并通过ViewModel来连接两者。MVVM的目标是实现可测试性、可维护性和可复用性。 MVC&am…...

ElementUI组件的安装和使用
Element UI 是一款基于 Vue 2.0 的桌面端组件库,主要用于快速构建网站的前端部分。它提供了丰富的组件,如按钮、输入框、表格、标签页等,以及一些布局元素,如布局容器、分割线等。Element UI 的设计风格简洁,易于上手&…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...