当前位置: 首页 > news >正文

JUC并发编程之原子类

目录

1. 什么是原子操作

1.1 原子类的作用

1.2 原子类的常见操作

原子类的使用注意事项


并发编程是现代计算机应用中不可或缺的一部分,而在并发编程中,处理共享资源的并发访问是一个重要的问题。为了避免多线程访问共享资源时出现竞态条件(Race Condition)等问题,Java提供了一组原子类(Atomic Classes)来支持线程安全的操作。

1. 什么是原子操作

在并发编程中,原子操作是不可被中断的一个或一系列操作,要么全部执行成功,要么全部不执行,不会出现部分执行的情况。原子操作能够保证在多线程环境下,对共享资源的操作不会相互干扰,从而确保数据的一致性和可靠性。

1.1 原子类的作用

Java提供了一组原子类,位于java.util.concurrent.atomic包中,用于在多线程环境下进行原子操作。这些原子类利用底层的硬件支持或自旋锁等机制来实现线程安全的操作,避免了显式地使用synchronized关键字等锁机制,从而提高了并发性能。

原子类的作用主要有以下几点:

  1. 提供线程安全的操作: 原子类提供了一些常见的操作,如读取、更新、比较交换等,这些操作在执行时不会受到其他线程的干扰,从而确保数据的一致性。

  2. 避免竞态条件: 使用原子类可以有效地避免多线程环境下的竞态条件问题,例如多个线程同时对同一个变量进行操作,可能导致不可预测的结果。

  3. 提高性能: 原子类在实现上利用了一些底层的技术,避免了传统锁机制的开销,因此在某些情况下可以提供更好的性能。

1.2 原子类的常见操作

1. AtomicBoolean

AtomicBoolean类提供了原子的布尔值操作,支持原子的设置和获取操作。

AtomicBoolean atomicBoolean = new AtomicBoolean(true);boolean currentValue = atomicBoolean.get(); // 获取当前值
boolean updatedValue = atomicBoolean.compareAndSet(true, false); // 如果当前值为true,则设置为false

 

2. AtomicInteger 和 AtomicLong

AtomicIntegerAtomicLong分别提供了原子的整数和长整数操作,包括增加、减少、获取等操作。

AtomicInteger atomicInt = new AtomicInteger(0);int currentValue = atomicInt.get(); // 获取当前值
int newValue = atomicInt.incrementAndGet(); // 增加1并返回新值
int updatedValue = atomicInt.addAndGet(5); // 增加5并返回新值

3. AtomicReference

AtomicReference允许在原子级别上操作引用类型的数据。它提供了getsetcompareAndSet等方法。

AtomicReference<String> atomicRef = new AtomicReference<>("initial value");String currentValue = atomicRef.get(); // 获取当前值
boolean updated = atomicRef.compareAndSet("initial value", "new value"); // 如果当前值为"initial value",则设置为"new value"

 

4. AtomicStampedReference

AtomicStampedReference是对AtomicReference的扩展,它还包含一个时间戳,用于解决ABA问题(即一个值被修改为另一个值,然后又被修改回原来的值,但是在这之间可能发生了其他的变化)。

AtomicStampedReference<String> atomicStampedRef = new AtomicStampedReference<>("initial value", 0);int currentStamp = atomicStampedRef.getStamp(); // 获取当前时间戳
String currentValue = atomicStampedRef.getReference(); // 获取当前值
boolean updated = atomicStampedRef.compareAndSet("initial value", "new value", 0, 1); // 如果当前值为"initial value"且时间戳为0,则设置为"new value"和时间戳为1

5. AtomicArray

AtomicArray类允许在原子级别上操作数组元素,提供了针对数组元素的原子更新操作。

AtomicIntegerArray atomicIntArray = new AtomicIntegerArray(5);int currentValue = atomicIntArray.get(2); // 获取索引为2的元素值
atomicIntArray.set(3, 10); // 设置索引为3的元素值为10
int updatedValue = atomicIntArray.getAndAdd(1, 5); // 增加索引为1的元素值,并返回旧值

6. AtomicReferenceFieldUpdater

AtomicReferenceFieldUpdater是Java中的一个工具类,用于进行原子更新类的引用类型字段的操作。它允许您在不使用锁的情况下对指定的引用字段进行原子操作,类似于AtomicFieldUpdater,但专门用于引用类型的字段。AtomicReferenceFieldUpdater主要用于确保在多线程环境下对引用字段的操作是线程安全的,并且可以提供更好的性能。

AtomicReferenceFieldUpdater适用于以下场景:

  1. 当您需要在不使用锁的情况下对特定类的引用字段进行原子更新时。

  2. 当引用字段的访问修饰符是volatile,以确保多线程之间的可见性。

  3. 当您希望在多个实例之间共享原子更新引用字段的功能,而不是整个对象。

要使用AtomicReferenceFieldUpdater,首先需要创建一个AtomicReferenceFieldUpdater的实例。这可以通过调用AtomicReferenceFieldUpdater.newUpdater(Class<T> tclass, Class<V> vclass, String fieldName)方法来实现,其中:

  • tclass是包含字段的类的Class对象。
  • vclass是字段的引用类型的Class对象。
  • fieldName是要进行原子操作的引用字段的名称。

以下是一个示例代码片段,演示如何创建和使用AtomicReferenceFieldUpdater实例:

public class AtomicReferenceFieldUpdaterExample {public static class Student {public volatile String name;}public static void main(String[] args) {Student student = new Student();AtomicReferenceFieldUpdater<Student, String> updater =AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");updater.set(student, "Alice"); // 原子地设置name字段为"Alice"String updatedName = updater.get(student); // 原子地获取name字段的值System.out.println("Updated Name: " + updatedName);}
}

AtomicReferenceFieldUpdater提供了一系列的原子操作方法,用于对指定引用字段进行原子更新。这些方法包括:

  • boolean compareAndSet(T obj, V expect, V update):如果当前值等于expect,则将字段更新为update,返回是否更新成功。

  • V getAndSet(T obj, V newValue):将字段更新为newValue,并返回之前的值。

  • V getAndUpdate(T obj, UnaryOperator<V> updateFunction):使用给定的更新函数更新字段,并返回更新前的值。

  • V updateAndGet(T obj, UnaryOperator<V> updateFunction):使用给定的更新函数更新字段,并返回更新后的值。

  • V getAndAccumulate(T obj, V x, BinaryOperator<V> accumulatorFunction):使用给定的累加函数将字段与x进行累加操作,并返回更新前的值。

  • V accumulateAndGet(T obj, V x, BinaryOperator<V> accumulatorFunction):使用给定的累加函数将字段与x进行累加操作,并返回更新后的值。

7. LongAdder

LongAdder是Java并发包中提供的一种用于高并发场景下对long类型进行累加操作的工具类。与传统的AtomicLong相比,LongAdder在高并发情况下通常能够提供更好的性能,因为它采用了一种分段的方式来减少竞争。LongAdder的引入主要是为了应对高并发累加操作的性能瓶颈,特别是在多核处理器上。

LongAdder在高并发场景下的主要优势在于分段累加,以及对热点数据的分离处理。传统的AtomicLong在高并发情况下可能会因为多线程之间的竞争而导致性能下降,而LongAdder通过将累加操作分成多个段,每个段维护一个计数器,从而减少了竞争。

另外,LongAdder还引入了一种称为“分离器”(Cell)的机制。分离器是计数器的基本单元,每个线程在累加时会选择一个分离器进行操作,这避免了多线程频繁地竞争同一个计数器,从而减少了竞争带来的开销。

要使用LongAdder,只需要简单地创建一个LongAdder的实例即可:

LongAdder longAdder = new LongAdder();

 

LongAdder提供了一些常用的方法来进行累加操作:

  • void add(long x):将指定的值添加到计数器中。

  • void increment():将计数器增加1。

  • void decrement():将计数器减少1。

  • long sum():返回当前计数器的总和。

  • void reset():将计数器重置为0。

  • void addThenReset(long x):将指定的值添加到计数器中,然后将计数器重置为0。

原子类的使用注意事项

  1. 性能考虑: 虽然原子类可以提供一定程度的性能优势,但并不是适用于所有情况。在高并发场景下,考虑使用原子类;而在低并发、性能要求不高的情况下,可能传统的同步机制更加合适。

  2. CAS操作的限制: 原子类的底层实现主要依赖于CAS(Compare-And-Swap)操作,这是一种乐观锁机制。然而,CAS操作可能会在竞争激烈的情况下导致自旋等待,影响性能。

  3. ABA问题: 原子类的CAS操作可能存在ABA问题,即一个值从A变为B,然后又从B变为A,这时CAS操作可能会错误地认为值没有发生变化。可以使用AtomicStampedReference来解决此问题。

  4. 复合操作的原子性: 原子类的单个操作是原子的,但多个操作的组合并不一定是原子的。例如,AtomicIntegerincrementAndGet操作是原子的,但在使用时仍然需要考虑复合操作的原子性。

  5. 适用范围: 原子类适用于简单的原子操作,但并不适用于复杂的业务逻辑。对于复杂的操作,可能需要使用锁等更高级的同步机制来确保线程安全。

相关文章:

JUC并发编程之原子类

目录 1. 什么是原子操作 1.1 原子类的作用 1.2 原子类的常见操作 原子类的使用注意事项 并发编程是现代计算机应用中不可或缺的一部分&#xff0c;而在并发编程中&#xff0c;处理共享资源的并发访问是一个重要的问题。为了避免多线程访问共享资源时出现竞态条件&#xff0…...

测试设计中隐藏的边界有哪些?

概述&#xff1a;边界值分析是测试设计一个稳定的部分&#xff0c;但是对黑盒测试人员来讲有时候边界并不是那么明显。这些不明显的边界被称作隐藏的边界。本文提供几个隐藏的边界的例子&#xff0c;还有一些以让隐藏边界显露来设计测试计划的要点方法。 使用边界值分析和等价…...

领航优配:暑期旅游市场热度持续攀升,相关公司业绩有望持续释放

到发稿&#xff0c;海看股份涨停&#xff0c;中广天择、探路者、众信旅行等涨幅居前。 8月8日&#xff0c;在线旅行板块震动上涨&#xff0c;到发稿&#xff0c;海看股份涨停&#xff0c;中广天择、探路者、众信旅行等涨幅居前。 今年以来&#xff0c;国内旅行商场逐渐恢复。文…...

基于 CentOS 7 构建 LVS-DR 集群 及 配置nginx负载均衡

一、构建LVS-DR集群 1、主机规划 Node01&#xff1a;PC Node02&#xff1a;LVS Node03、Node04&#xff1a;Webserver 2、部署环境 2.1 在Node02上配置 2.1.1 安装ipvsadm管理软件按 [rootlocalhost ~]# yum install -y ipvsadm 2.1.2 配置VIP [rootlocalhost ~]# if…...

docker搭建在线Markdown服务器

1.安装docker 2.编写docker-compose.yml version: "3" services:database:image: postgres:11.6-alpineenvironment:- POSTGRES_USERcodimd- POSTGRES_PASSWORDchange_password- POSTGRES_DBcodimdvolumes:- "database-data:/var/lib/postgresql/data"re…...

打靶练习:WestWild 1.1(一个简单但不失优雅的Ubuntu靶机)

主机发现和nmap信息收集 //主机发现 sudo nmap -sn 192.168.226.0/24 //扫描整个C段//端口扫描//初步扫描 sudo nmap -sT --min-rate 10000 -p- 192.168.226.131 -oA nmapscan/ports //用TCP的三次握手&#xff0c;以速率10000扫描1-65535端口&#xff0c;扫描结果以全格式…...

【2.3】Java微服务:sentinel服务哨兵

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a;Java微服务 ✨特色专栏&#xff1a; 知识分享 &…...

【C++】开源:abseil-cpp基础组件库配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍abseil-cpp基础组件库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#…...

【GPT-3 】创建能写博客的AI工具

一、说明 如何使用OpenAI API&#xff0c;GPT-3和Python创建AI博客写作工具。 在本教程中&#xff0c;我们将从 OpenAI API 中断的地方继续&#xff0c;并创建我们自己的 AI 版权工具&#xff0c;我们可以使用它使用 GPT-3 人工智能 &#xff08;AI&#xff09; API 创建独特的…...

[保研/考研机试] KY35 最简真分数 北京大学复试上机题 C++实现

题目链接&#xff1a; 最简真分数https://www.nowcoder.com/share/jump/437195121691719749588 描述 给出n个正整数&#xff0c;任取两个数分别作为分子和分母组成最简真分数&#xff0c;编程求共有几个这样的组合。 输入描述&#xff1a; 每组包含n&#xff08;n<600&…...

算法备案后,企业需要做什么?合规与执行挑战

随着技术的迅猛发展&#xff0c;算法已经成为多数企业核心竞争力的一部分。但在技术进步的同时&#xff0c;我们也面临了算法透明度、公平性以及安全性的问题。因此&#xff0c;许多国家已经开始实施算法备案制度&#xff0c;以确保算法的应用满足一定的标准和规范。但在完成算…...

云原生应用程序的自动化管理和编排

云原生应用程序是一种为云环境设计的应用程序&#xff0c;它采用了如微服务、容器、可伸缩性和自动化等特性&#xff0c;以最大限度地提高效率和响应速度。本文将深入探讨云原生应用如何实现自动化管理和编排。 容器化 容器技术&#xff0c;如Docker&#xff0c;是云原生应用程…...

Spring项目整合过滤链模式~实战应用

代码下载 设计模式代码全部在gitee上,下载链接: https://gitee.com/xiaozheng2019/desgin_mode.git 日常写代码遇到的囧 1.新建一个类,不知道该放哪个包下 2.方法名称叫A,干得却是A+B+C几件事情,随时隐藏着惊喜 3.想复用一个方法,但是里面嵌套了多余的逻辑,只能自己拆出来…...

FFmpeg常见命令行(五):FFmpeg滤镜使用

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》&#xff0c;结合我自己的工作学习经历&#xff0c;我准备写一个音视频系列blog。本文是音视频系…...

网络编程 tcp udp http编程流程 网络基础知识

讲解 网络基础知识网络编程tcp编程流程图示理解bind和accept函数理解监视套接字和链接套接字理解linux和window下的编程实现tcp特点 udp编程流程图示理解udp特点 http编程流程图示理解编程实现-网站服务器 网络基础知识 OSI分层&#xff1a;应用层 表示层 会话层 传输层 网络层…...

LaTeX基础学习笔记

LaTeX是一个文本编辑器。其类似于markdown&#xff0c;使用特殊标记和代码来修改文本格式&#xff0c;创建特殊字符等。可以使用overleaf在线LaTex编辑器编写LaTeX并转换为pdf文件&#xff08;https://www.overleaf.com/&#xff09; 同时推荐一个网站http://detexify.kirelab…...

zookeeper和kafka

目录 一、zookeeper理论 1.1、zookeeper定义 1.2、zookeeper工作机制 1.3、zookeeper特点 1.4、zookeeper的数据结构 1.5、zookeeper应用场景 1.6、zookeeper的选举机制 二、部署Zookeeper 集群 2.1、环境准备 2.2、安装 Zookeeper 2.3、修改配置文件 2.4、配置…...

服务器无法加载海康sdk依赖的问题

首先遇到的jna.jar和examples.jar无法加载的问题&#xff0c;尝试了很多方法无效&#xff0c;以下方法实测有效 其次是动态链接库无法加载的问题&#xff0c;而且是播放库&#xff0c;我的方法比较简单&#xff0c;netsdk加载出来就行了&#xff0c;播放库用不到&#xff0c;删…...

brew+nginx配置静态文件服务器

背景 一下子闲下来了&#xff0c;了解的我的人都知道我闲不下来。于是&#xff0c;我在思考COS之后&#xff0c;决定自己整一个本地的OSS&#xff0c;实现静态文件的访问。那么&#xff0c;首屈一指的就是我很熟的nginx。也算是个小复习吧&#xff0c;复习一下nginx代理静态文…...

JavaFx异常: Not on FX application thread; currentThread = Timer-0

我的定时器任务中有两个控件&#xff1a; FXML TextArea Display; FXML Label Label_Display; 执行下方代码会抛出&#xff1a;Exception in thread "Timer-0" java.lang.IllegalStateException: Not on FX application thread; currentThread Timer-0 Timer_tas…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式

pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图&#xff0c;如果边框加在dom上面&#xff0c;pdf-lib导出svg的时候并不会导出边框&#xff0c;所以只能在echarts图上面加边框 grid的边框是在图里…...

标注工具核心架构分析——主窗口的图像显示

&#x1f3d7;️ 标注工具核心架构分析 &#x1f4cb; 系统概述 主要有两个核心类&#xff0c;采用经典的 Scene-View 架构模式&#xff1a; &#x1f3af; 核心类结构 1. AnnotationScene (QGraphicsScene子类) 主要负责标注场景的管理和交互 &#x1f527; 关键函数&…...

Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集

目录 一、引言&#xff1a;当爬虫遭遇"地域封锁"二、背景解析&#xff1a;分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计&#xff1a;Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...