Java并发基础:原子类之AtomicIntegerFieldUpdater全面解析

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

代码解释:

  1. 定义一个名为MyObject的静态内部类,该类有一个volatile字段value
  2. 创建一个AtomicIntegerFieldUpdater类的实例updater,该实例将用于原子地更新MyObject类的value字段。
  3. main方法中,创建了MyObject的实例,并使用updater原子地增加和设置value字段的值。
  4. 使用System.out.println来输出value字段的初始值、增加后的值和设置为100后的值。

AtomicIntegerFieldUpdater核心API

AtomicIntegerFieldUpdater类是Java的java.util.concurrent.atomic包中的一个工具类,这个类的主要是用于原子地更新指定对象的指定volatile字段,以下是该类中一些主要方法的含义:

  1. newUpdater(Class<T> tclass, String fieldName):
    这是一个静态方法,用于创建一个新的AtomicIntegerFieldUpdater,它能够以原子方式更新给定类的指定名称的volatile字段,tclass是字段所在类的Class对象,fieldName是要更新的字段的名称。
  2. get(T obj):
    这个方法获取指定对象的volatile字段的当前值,obj是包含要获取字段的对象。
  3. set(T obj, int newValue):
    这个方法以原子方式设置指定对象的volatile字段的值为newValueobj是包含要设置字段的对象,newValue是要设置的新值。
  4. lazySet(T obj, int newValue):
    这个方法最终将设置指定对象的volatile字段的值为newValue,但它允许之后的内存操作重排序,也就是说这个操作可能不是立即对其他线程可见的,它通常用于提高性能,但牺牲了一些一致性保证。
  5. getAndSet(T obj, int newValue):
    这个方法以原子方式设置指定对象的volatile字段的值为newValue,并返回该字段的旧值,obj是包含要设置字段的对象,newValue是要设置的新值。
  6. getAndAdd(T obj, int delta):
    这个方法以原子方式将给定值delta添加到指定对象的volatile字段的当前值,并返回更新前的值,obj是包含要添加字段的对象,delta是要添加的值。
  7. incrementAndGet(T obj):
    这个方法以原子方式将指定对象的volatile字段的当前值增加1,并返回更新后的值,obj是包含要增加字段的对象。
  8. decrementAndGet(T obj):
    这个方法以原子方式将指定对象的volatile字段的当前值减少1,并返回更新后的值,obj是包含要减少字段的对象。
  9. addAndGet(T obj, int delta):
    这个方法以原子方式将给定值delta添加到指定对象的volatile字段的当前值,并返回更新后的值,obj是包含要添加字段的对象,delta是要添加的值。
  10. 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类的底层操作。

实现原理

  1. Java内存模型(JMM):使用Java内存模型保证了多线程之间变量的可见性和原子性操作,使用volatile关键字确保了一个线程对变量的修改对其他线程是立即可见的,并且禁止了指令重排。
  2. Unsafe类:
    AtomicIntegerFieldUpdater的底层实现依赖于sun.misc.Unsafe类,该类提供了低级别的、非安全的、操作系统级别的访问方法,它可以直接访问内存、创建对象、数组等,而不受Java访问控制的限制。
  3. 反射:
    AtomicIntegerFieldUpdater使用反射来获取要更新的字段的Field对象,然后通过Unsafe类直接操作这个字段的内存地址。
  4. 原子操作:
    Unsafe类提供了一系列原子操作方法,如compareAndSwapInt,这是一个基于硬件支持的原子比较并交换(CAS)操作,CAS操作包括三个参数:一个内存位置(V)、预期原值(A)和新值(B),如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置的值更新为新值B,否则,处理器不做任何操作,无论哪种情况,它都会在CAS指令之前返回该位置的值,这一过程是原子的,也就是说在执行过程中不会被其他线程打断。

底层算法

AtomicIntegerFieldUpdater的底层算法主要基于CAS操作来实现原子性更新,以incrementAndGet方法为例:

  1. 使用一个do-while循环来尝试更新字段的值。
  2. 在循环体内,首先使用Unsafe类的getIntVolatile方法获取当前字段的值。
  3. 计算新的值(当前值 + 1)。
  4. 使用Unsafe类的compareAndSwapInt方法尝试将字段的值从当前值更新为新值,如果成功,则退出循环并返回新值;如果失败(说明其他线程已经修改了该字段的值),则继续循环。

这种基于CAS的算法是一种无锁算法,也称为乐观锁算法,它不需要获取和释放锁,而是通过不断重试来确保更新的原子性,在高并发环境下,这种算法通常比传统的基于锁的算法具有更好的性能。

学习总结

Java并发基础:原子类之AtomicIntegerFieldUpdater全面解析 - 程序员古德

AtomicIntegerFieldUpdater类允许以原子方式更新对象的某个volatile字段,而无需使用synchronized关键字,这样做的优点在于减少了锁的竞争,提升了多线程环境下的性能,并且使用简单,只需通过反射指定字段即可。

但是,由于使用了反射,所以字段必须是可访问的,这可能会破坏封装性,并且,它只能更新volatile类型的字段,对于其他类型的字段或者非volatile字段则无能为力。

在使用AtomicIntegerFieldUpdater时,建议仅在确实需要原子性更新且性能是关键因素时使用,并且要要注意保持字段的可访问性,并确保字段是volatile类型的。

关注我,每天学习互联网编程技术 - 程序员古德

END!
END!
END!

往期回顾

精品文章

Java并发基础:concurrent Flow API全面解析

Java并发基础:CopyOnWriteArraySet全面解析

Java并发基础:ConcurrentSkipListMap全面解析

Java并发基础:ConcurrentSkipListSet全面解析!

Java并发基础:SynchronousQueue全面解析!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

选择VR全景行业,需要了解哪些内容?

近年来&#xff0c;随着虚拟现实、增强现实等技术的持续发展&#xff0c;VR全景消费市场得以稳步扩张。其次&#xff0c;元宇宙行业的高速发展&#xff0c;也在进一步拉动VR全景技术的持续进步&#xff0c;带动VR产业的高质量发展。作为一种战略性的新兴产业&#xff0c;国家和…

【vue vue-seamless-scroll】解决vue-seamless-scroll鼠标悬浮才滚动或者只滚动一次就失效的问题

解决问题&#xff1a;使用vue-seamless-scroll发现只有鼠标悬浮上去才滚动&#xff0c;而且滚动一次停止了 目标效果&#xff1a; 解决方案&#xff1a; 最后发现是因为数据需要在页面挂载好就赋值&#xff0c;否则页面在加载完成后&#xff0c;数据无法自动滚动。但因为数据…

防火墙内容安全笔记

目录 DFI和DPI IDS和IPS 签名 AV URL过滤 HTTPS过滤 内容过滤 文件类型过滤 文件内容过滤 邮件过滤 VPN概述 DFI和DPI DFI和DPI技术 --- 深度检测技术 DPI DPI --- 深度包检测技术 --- 主要针对完整的数据包&#xff08;数据包分片&#xff0c;分段需要重组&#…

百亿美金的设计,深度剖析 GitLab 的 Postgres 数据库 schema

原文链接 这篇文章写于 2022 年&#xff0c;前一年 GitLab 刚好完成 IPO。目前 GitLab 市值超过 100 亿美金&#xff0c;它的所有收入都来源于同名产品 GitLab&#xff0c;而这篇文章就是全面分析 GitLab 这个产品的数据库 schema。 我花了一些时间研究 GitLab 的 Postgres sch…

【ArcGIS Pro二次开发】(82):玩个花活_控规指标块生成

一、要实现的效果 废话不多说&#xff0c;这次要实现的是类似控规指标块的标注&#xff1a; 这里只是示例&#xff0c;用了5个格子&#xff0c;做成9个格子也是可以的。 实现这个效果最关键的是要用到Pro中的复合标注。 关于复合标注的用法可以搜一下帮助里的【使用复合注释…

网站常见的攻击类型有什么,如何针对性防护

在互联网时代&#xff0c;几乎每个网站都存在着潜在的安全威胁。这些威胁可能来自人为失误&#xff0c;也可能源自网络犯罪团伙所发起的复杂攻击。无论攻击的本质如何&#xff0c;网络攻击者的主要动机通常是谋求经济利益。这意味着不管是什么网站类型潜在的威胁一直都存在。 在…

关于2025年的AMC8竞赛,你可能感兴趣的一些问题和信息

最近几天&#xff0c;我分享了一些历年的AMC8数学竞赛真题和解析&#xff0c;有一些家长和孩子第一次接触&#xff0c;产生了浓厚的兴趣&#xff0c;并且问了许多关于AMC8的问题。为了帮助更多家长和孩子了解这个比赛&#xff0c;我把常见的问题&#xff0c;以及大家可能感兴趣…

[java基础揉碎]封装

封装介绍 封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部&#xff0c;程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。 比如说我们用遥控器对电视的操作, 我们按电视机的开关键, 其实开关背后是一个复杂的过程,…

Codeforces Round 927 (Div. 3)

F. Feed Cats 题目大意 给一长度为的数轴&#xff0c;个区间在数轴上选取一些点作为特殊点在满足个区间中&#xff0c;每个区间内只能有一个特殊点问最多能选多少个特殊点 解题思路 对于每个点有放或不放两种状态考虑表示位置可能放或不放的最优结果若不放&#xff0c;若放…

unity hub初学配置

1、安装Unity Hub 2、设置中文 3、安装编辑器 4、新建项目 5、新建完成后进入编辑器 6、 编辑器设置中文 editPreferencesLanguages选择中文

数据安全治理实践路线(上)

基于以上数据安全治理实践理念&#xff0c;可以按照自顶向下和自底向上相结合的思路推进实践过程。一方面&#xff0c;组织自顶向下,以数据安全战略规划为指导,以规划、建设、运营、优化为主线&#xff0c;围绕构建数据安全治理体系这一核心&#xff0c;从组织架构、制度流程、…

SQL注入:使用预编译防御SQL注入时产生的问题

目录 前言 模拟预编译 真正的预编译 预编译中存在的SQL注入 宽字节 没有进行参数绑定 无法预编译的位置 前言 相信学习过SQL注入的小伙伴都知道防御SQL注入最好的方法&#xff0c;就是使用预编译也就是PDO是可以非常好的防御SQL注入的&#xff0c;但是如果错误的设置了…

【C语言】socket 层到网络接口的驱动程序之间的函数调用过程

一、socket 层到网络接口的驱动程序之间的函数调用过程概述 在 Linux 操作系统中&#xff0c;socket 层到网络接口的驱动程序之间的函数调用过程相对复杂&#xff0c;涉及多个层次的交互。以下是一个简化的概述&#xff0c;描述数据从 socket 传递到硬件驱动&#xff0c;再到硬…

新书推荐:《分布式商业生态战略:未来数字商业新逻辑与企业数字化转型新策略》

近两年&#xff0c;商业经济环境的不确定性越来越明显&#xff0c;市场经济受到疫情、技术、政策等多方因素影响越来越难以预测&#xff0c;黑天鹅事件时有发生。在国内外经济方面&#xff0c;国际的地缘政治对商业经济产生着重大的影响&#xff0c;例如供应链中断&#xff0c;…

PostgreSQL 实体化视图的使用

上周的教程中&#xff0c;通过 DVD Rental Database 示例&#xff0c;让我们了解了在 PostgreSQL 中创建实体化视图的过程。正如我们所了解的&#xff0c;PostgreSQL 实体化视图提供了一种强大的机制&#xff0c;通过预计算和存储查询结果集为物理表来提高查询性能。接下来的内…

C#_扩展方法

简述&#xff1a; 扩展方法所属类必需是静态类&#xff08;类名依据规范通常为XXXExtension&#xff0c;XXX为被扩展类&#xff09;扩展方法必需是公有的静态方法扩展方法的首个参数由this修饰&#xff0c;参数类型为被扩展类型 示例&#xff1a; static class DoubleExtens…

vue实现拖拽(vuedraggable)

实现效果: 左侧往右侧拖动&#xff0c;右侧列表可以进行拖拽排序。 安装引用&#xff1a; npm install vuedraggable import draggable from vuedraggable 使用&#xff1a; data数据&#xff1a; componentList: [{groupName: 考试题型,children: [{componentType: danxua…

【基础】提高前端的增益

低噪声&#xff0c;低偏移电压&#xff0c;低漂移-当你把信号链前端的增益提高后&#xff0c;所有的这些精密小信号处理的目标变得很简单。 这是一个很简单的概念。如图1所示&#xff0c;第二级的误差将除以第一级的增益。比如&#xff0c;第一级增益适度&#xff0c;值为10&a…

制造业客户数据安全解决方案(终端安全/文件加密/介质管理等)

针对前文制造业客户数据安全解决方案&#xff08;数据防泄密需求分析&#xff09;提到的泄密风险&#xff0c;本文详细介绍一套完整、合理的解决方案&#xff0c;通过该方案构建公司数据安全防护边界&#xff0c;自动加密、全方位保护数据安全。 PC端&#xff1a;https://isite…

Qt开发:MAC安装qt、qtcreate(配置桌面应用开发环境)

安装qt-creator brew install qt-creator安装qt brew install qt查看qt安装路径 brew info qtzhbbindembp ~ % brew info qt > qt: stable 6.6.1 (bottled), HEAD Cross-platform application and UI framework https://www.qt.io/ /opt/homebrew/Cellar/qt/6…