java原子操作类

在并发编程中,Java 提供了一组原子操作类来确保线程安全,这些类位于 java.util.concurrent.atomic 包中。这些类通过底层硬件支持的CAS(Compare-And-Swap,比较并交换)机制,能够在无锁的情况下实现对变量的安全更新。这种无锁机制不仅能确保线程安全,还能避免传统锁带来的上下文切换开销,极大提高了并发性能。

1. 原子操作的背景

在多线程编程中,多个线程可能同时操作共享的变量。如果不使用同步机制(如 synchronizedLock),多个线程的并发修改可能导致数据不一致的情况。为了解决这个问题,Java 提供了 Atomic 类,它们支持一种非阻塞的原子性操作。

  • 原子性:是指在一次操作过程中,中间不会被其他线程打断,保证操作的完整性。
  • CAS:原子操作类依赖 CAS 实现线程安全,CAS 是一种乐观锁机制,它比较当前变量的值与预期值,如果相等就更新,否则重试。这种机制通常会比阻塞锁更加高效。

2. 原子操作类的分类

Java 提供了多种原子操作类,主要分为以下几类:

  1. 原子更新基本类型

    • AtomicInteger:对 int 类型的原子操作。
    • AtomicLong:对 long 类型的原子操作。
    • AtomicBoolean:对 boolean 类型的原子操作。
  2. 原子更新数组类型

    • AtomicIntegerArray:对 int[] 数组的原子操作。
    • AtomicLongArray:对 long[] 数组的原子操作。
    • AtomicReferenceArray<E>:对对象数组的原子操作。
  3. 原子更新引用类型

    • AtomicReference<V>:对普通对象引用的原子操作。
    • AtomicStampedReference<V>:带有版本戳的原子引用,可以解决 ABA 问题。
    • AtomicMarkableReference<V>:带有标记位的原子引用。
  4. 原子更新对象属性类型

    • AtomicIntegerFieldUpdater<T>:对 int 类型的某个类的字段进行原子更新。
    • AtomicLongFieldUpdater<T>:对 long 类型的某个类的字段进行原子更新。
    • AtomicReferenceFieldUpdater<T,V>:对对象引用类型的某个类的字段进行原子更新。

3. 常用原子操作类详解

3.1 AtomicInteger

AtomicInteger 是最常用的原子操作类之一,它用于对 int 类型的变量进行原子更新。常见的方法包括:

  • get():获取当前值。
  • set(int newValue):设置新值。
  • compareAndSet(int expect, int update):如果当前值等于 expect,则将其更新为 update
  • getAndIncrement():以原子方式将当前值加 1,并返回旧值。
  • incrementAndGet():以原子方式将当前值加 1,并返回新值。

示例代码:

import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerExample {private static final AtomicInteger counter = new AtomicInteger(0);public static void main(String[] args) {// 多线程并发递增for (int i = 0; i < 10; i++) {new Thread(() -> {int newValue = counter.incrementAndGet(); // 原子递增System.out.println(Thread.currentThread().getName() + " - Counter: " + newValue);}).start();}}
}

在上面的代码中,多个线程可以并发递增 counter,且不需要使用锁来保证线程安全,因为 AtomicInteger 使用 CAS 实现了无锁的原子性递增。

3.2 AtomicReference

AtomicReference 用于对引用类型(对象)的原子更新。它与 AtomicInteger 类似,但操作的是对象而非基本类型。常用方法包括:

  • get():获取当前对象的引用。
  • set(V newValue):设置新引用。
  • compareAndSet(V expect, V update):如果当前引用等于 expect,则将其更新为 update

示例代码:

import java.util.concurrent.atomic.AtomicReference;public class AtomicReferenceExample {private static final AtomicReference<String> ref = new AtomicReference<>("Initial Value");public static void main(String[] args) {// 多线程并发更新引用for (int i = 0; i < 3; i++) {new Thread(() -> {String oldValue = ref.get();String newValue = oldValue + " Updated by " + Thread.currentThread().getName();if (ref.compareAndSet(oldValue, newValue)) {System.out.println(Thread.currentThread().getName() + " - Updated: " + newValue);} else {System.out.println(Thread.currentThread().getName() + " - Update failed");}}).start();}}
}

这个示例展示了如何使用 AtomicReference 来保证多个线程并发更新对象引用时的原子性。compareAndSet 方法确保只有预期的引用被更新,避免了并发修改问题。

3.3 AtomicStampedReference

AtomicStampedReferenceAtomicReference 的扩展,它解决了ABA 问题。ABA 问题是指在并发环境中,一个变量可能被修改为旧值,然后再次被修改回来,但这个变化可能会被忽略,因为在 CAS 比较时,值没有发生变化。AtomicStampedReference 通过为每次操作打上“戳”,来检测是否出现 ABA 问题。

示例代码:

import java.util.concurrent.atomic.AtomicStampedReference;public class AtomicStampedReferenceExample {private static final AtomicStampedReference<String> stampedRef = new AtomicStampedReference<>("Initial", 0);public static void main(String[] args) {int[] stampHolder = new int[1];String oldValue = stampedRef.get(stampHolder); // 获取当前值和戳int stamp = stampHolder[0]; // 当前戳System.out.println("Old Value: " + oldValue + ", Stamp: " + stamp);// 更新值和戳boolean result = stampedRef.compareAndSet(oldValue, "Updated", stamp, stamp + 1);if (result) {System.out.println("Update success. New Value: " + stampedRef.getReference() + ", New Stamp: " + stampedRef.getStamp());} else {System.out.println("Update failed.");}}
}

在这个示例中,AtomicStampedReference 通过戳来解决了 ABA 问题。每次修改时都会比较值和戳,确保引用的值和版本戳同时满足预期。

3.4 AtomicIntegerArray

AtomicIntegerArray 是对 int 数组的原子操作类。它支持对数组中每个元素进行原子操作,而不需要对整个数组加锁。常见的方法包括:

  • get(int i):获取数组第 i 个元素的值。
  • set(int i, int newValue):设置第 i 个元素的新值。
  • getAndIncrement(int i):将数组第 i 个元素加 1,并返回旧值。

示例代码:

import java.util.concurrent.atomic.AtomicIntegerArray;public class AtomicIntegerArrayExample {private static final AtomicIntegerArray atomicArray = new AtomicIntegerArray(5);public static void main(String[] args) {// 启动多个线程操作数组for (int i = 0; i < 5; i++) {int index = i;new Thread(() -> {int oldValue = atomicArray.getAndIncrement(index);System.out.println(Thread.currentThread().getName() + " - Index: " + index + ", Old Value: " + oldValue + ", New Value: " + atomicArray.get(index));}).start();}}
}

AtomicIntegerArray 允许多个线程安全地并发操作同一个数组的不同元素,而不会引发竞争条件。

4. CAS 操作原理

原子操作类的核心是 CAS 操作。CAS 全称为“Compare and Swap”,即比较并交换,它依赖于硬件支持来实现无锁并发控制。CAS 包含三个操作数:

  • 内存位置(V):即变量的内存地址。
  • 期望值(A):当前线程期望变量的值。
  • 新值(B):当前线程希望将变量更新为的新值。

CAS 的工作原理是:如果内存位置 V 的值与期望值 A 相等,则将内存位置

V 的值更新为 B;否则,不做任何操作。CAS 操作通常通过 CPU 指令(如 cmpxchg)来实现,是一种高效的无锁机制。

5. 应用场景与性能

5.1 应用场景
  • 计数器:使用 AtomicInteger 作为全局计数器,确保多线程下的准确性。
  • 对象引用更新AtomicReference 可用于安全更新共享资源的引用,避免竞争条件。
  • 数组更新AtomicIntegerArray 用于高并发场景中对数组元素的安全更新。
  • ABA 问题解决:在并发环境中,使用 AtomicStampedReference 可以防止 ABA 问题。
5.2 性能

原子操作类由于采用 CAS 无锁机制,通常在高并发场景下性能优于传统的锁机制。特别是在多核处理器上,CAS 操作能避免上下文切换的开销,使得其在高频率的读写操作中表现更加优异。

6. 总结

Java 的原子操作类通过无锁的方式保证了线程安全,它们提供了对基本类型、数组、引用等的原子操作,在并发环境下既保证了数据的一致性,又避免了传统锁机制带来的性能损失。CAS 机制是原子操作类的核心,使得这些类在高并发场景中表现出色。合理使用这些类,能够在多线程编程中极大提升应用的并发性能。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

OpenAi assistant run always fails when called from PHP

题意&#xff1a;从 PHP 调用时&#xff0c;OpenAI 助理运行总是失败。 问题背景&#xff1a; The runs I create with the openai-php library fail direct in 100% of cases. What am I doing wrong? I do not have much experience with php but this is the test script.…

VS2019配置C++版本的GDAL

VS2019配置GDAL教程 【特别注意】 vs2019编译好的GDAL库是可以在VS2022上面使用的&#xff0c;我这边做项目已经测试过没有问题&#xff0c;所以vs2022使用vs2019编译的gdal没有问题。 【编译版本介绍】 由于GDAL在vs2019源码流程有点复杂&#xff0c;因此我们在这不做讲解…

【Git必看系列】—— 2024年前后端开发必须要知道的GitFlow工作流

自从 Linux 之父Linus Torvalds对当时的版本控制工具感到不满&#xff0c;亲自动手创造了 Git 以来&#xff0c;Git 已经逐渐在版本控制领域占据了主导地位。不论你的代码仓库托管在 GitHub 还是 GitLab&#xff0c;不论你用的是 SourceTree、GitKraken 这样的图形界面&#xf…

华为 HCIP-Datacom H12-821 题库 (25)

&#x1f423;博客最下方微信公众号回复题库,领取题库和教学资源 &#x1f424;诚挚欢迎IT交流有兴趣的公众号回复交流群 &#x1f998;公众号会持续更新网络小知识&#x1f63c; 1.以下哪些事件会导致 IS-IS 产生一个新的 LSP? A、邻接 Up 或Down B、引入的 IP 路由发送变…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)2.1-2.2

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第二周 深度卷积网络&#xff1a;实例探究&#xff08;Deep convolutional models: case studies&#xff09;2.1 为什么要进行实例探究&#xff1f;&#xff08;Why look at case studies?&…

PyTorch深度学习快速入门教程【土堆】基础知识篇

Juptyer 版本&#xff1a; Python 3.9.19Pytorch 2.4.1 (pytorch0) C:\Users\25694>conda install nb_conda_kernels(pytorch0) C:\Users\25694>jupyter notebook使用conda环境的pytorch&#xff1a; 成功解决python.exe无法找到程序入口 无法定位程序输入点 shifte…

【Python语言初识(一)】

一、python简史 1.1、python的历史 1989年圣诞节&#xff1a;Guido von Rossum开始写Python语言的编译器。1991年2月&#xff1a;第一个Python编译器&#xff08;同时也是解释器&#xff09;诞生&#xff0c;它是用C语言实现的&#xff08;后面&#xff09;&#xff0c;可以调…

茶思屋直播|TinyEngine+AI:聚焦主航道,在实践中探索低代码技术黑土地

低代码引擎使能开发者定制低代码平台。它是低代码平台的底座&#xff0c;提供可视化搭建页面等基础能力&#xff0c;既可以通过线上搭配组合&#xff0c;也可以通过cli创建个人工程进行二次开发&#xff0c;实时定制出自己的低代码平台。适用于多场景的低代码平台开发&#xff…

【C++ 学习】多态的基础和原理(10)

目录 前言1. 概念2. 多态的定义及实现2.1 多态的构成条件2.2 虚函数2.3 虚函数重写2.4 虚函数重写的例外2.4.1 协变2.4.1 析构函数的重写 2.5 多态调用和普通调用2.6 函数重写/函数隐藏/函数重载 的对比2.6.1 函数重写2.6.2 函数隐藏2.6.3 函数重载 2.7 C11 final 和override 3…

领域驱动DDD三种架构-分层架构、洋葱架构、六边形架构

博主介绍&#xff1a; 大家好&#xff0c;我是想成为Super的Yuperman&#xff0c;互联网宇宙厂经验&#xff0c;17年医疗健康行业的码拉松奔跑者&#xff0c;曾担任技术专家、架构师、研发总监负责和主导多个应用架构。 技术范围&#xff1a; 目前专注java体系&#xff0c;以及…

作为HR,如何考察候选人的沟通能力

如何考察候选人的沟通能力。沟通能力&#xff0c;这个听起来简单&#xff0c;实际上却是一个非常复杂的技能&#xff0c;它关乎到一个人能否有效地传递信息&#xff0c;理解他人&#xff0c;并且在团队中发挥积极的作用。 作为HR&#xff0c;我们应该怎样才能精准地把握住候选…

【Python语言初识(二)】

一、分支结构 1.1、if语句 在Python中&#xff0c;要构造分支结构可以使用if、elif和else关键字。所谓关键字就是有特殊含义的单词&#xff0c;像if和else就是专门用于构造分支结构的关键字&#xff0c;很显然你不能够使用它作为变量名&#xff08;事实上&#xff0c;用作其他…

网络:UDP协议

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 前言UDP协议报头和有效载荷分离的问题有效载荷向上交付的问题&#xff0c;也就是交给哪个进程&#xff1f;怎么确定把报文收全了&#xff1f;UDP报头是如何封装的呢&…

mybatisplus的多记录操作 批量删除和批量查询

1.批量查询 通过in查询 Testpublic void testBatchSelectByIds(){List<Integer> ids Arrays.asList(5,7);List<User> users userMapper.selectBatchIds(ids);log.info(users);} 2.批量删除 Testpublic void testBatchDelete(){List<Integer> ids Arrays…

VM VirtualBox虚拟机装Win11提示这台电脑不符合要求,怎么解决?

环境&#xff1a; VM VirtualBox WIN11 问题描述&#xff1a; VM VirtualBox虚拟机装WIN11提示这台电脑不符合要求 解决方案&#xff1a; 1.进入这个页面 2. 跳过win11安全验证 在键盘上按 Shift F10或者FnShift F10调出命令命令提示符&#xff0c; 键入 Regedit 并…

大数据处理从零开始————3.Hadoop伪分布式和分布式搭建

1.伪分布式搭建&#xff08;不会用&#xff0c;了解就好不需要搭建&#xff09; 这里接上一节。 1.1 伪分布式集群概述 伪分布式集群就是只有⼀个服务器节点的分布式集群。在这种模式中&#xff0c;我们也是只需要⼀台机器。 但与本地模式不同&#xff0c;伪分布式采⽤了分布式…

使用Locust进行接口性能测试:关联与参数化技巧分析

Locust是一款开源的Python性能测试工具&#xff0c;它可以模拟大量并发用户对网站或者其他接口进行压力测试 1. 关联&#xff1a;精确模拟用户操作 在某些场景下&#xff0c;我们需要将之前请求的响应参数关联到后续请求中&#xff0c;以模拟用户操作。这在会话管理&#xff…

数字工厂管理系统与MES系统在实际应用中有哪些区别

随着制造业的数字化转型步伐加快&#xff0c;数字工厂管理系统与制造执行MES系统作为两大关键工具&#xff0c;在实际应用中展现出了明显的差异。本文将从实际应用的角度&#xff0c;详细探讨这两种系统之间的主要区别。 数字工厂管理系统的实际应用 数字工厂管理系统侧重于对…

python检测keycloak证书连接报错问题

最近一直被keycloak的证书问题困扰了很久&#xff0c;老是提示ssl安全连接&#xff0c;由于不会java,只好硬着头皮用python测试。 我这里的证书是自己签注的证书&#xff0c;导入系统的是CA根证书。 from keycloak import KeycloakOpenID# 1. 配置 Keycloak 客户端 keycloak_o…

STM32F407ZGT6驱动sd卡+文件夹 并写入多组实时数据 基于cubemx生成

SD卡介绍 SD卡&#xff0c;全称Secure Digital卡&#xff0c;是一种常见的便携式存储设备&#xff0c;通常用于存储和传输数据。它是一种闪存存储卡。 TF卡&#xff08;TransFlash卡&#xff09; 又称MicroSD卡&#xff0c;MicroSD卡比SD卡小&#xff0c;通常只有SD卡的1/4大小…