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

并发编程学习(十一):原子数组、

1、数组类型的原子类     

原子数组类型,这个其实和AtomicInteger等类似,只不过在修改时需要指明数组下标。

CAS是按照==来根据地址进行比较。数组比较地址,肯定是不行的,只能比较下标元素。而比较下标元素,就和元素的类型有关系了。

java.util.concurrent.atomic中,原子类型数组有以下四种:

类名说明
AtomicIntegerArray提供对int[]数组元素的原子性更新操作
AtomicLongArray提供对long[]数组元素的原子性更新操作
AtomicReferenceArray提供对引用类型[]数组元素的原子性更新操作
AtomicBooleanArray原子更新布尔类型数组的元素

使用原子的方式更新数组里的某个元素。 

2、常用方法

        AtomicIntegerArrayAtomicLongArray的使用方式差别不大,AtomicReferenceArray因为他的参数为引用数组,所以跟前两个的使用方式有所不同。AtomicBooleanArray在生产中使用的很少。

本次只对AtomicLongArrayAtomicReferenceArray方法进行详细的介绍。

2.1、AtomicLongArray介绍

2.1.1、构造方法

方法名说明
AtomicLongArray(int length)创建给定长度的新 AtomicLongArray
AtomicLongArray(long[] array)创建与给定数组具有相同长度的新 AtomicLongArray,并从给定数组复制其所有元素

2.1.2、方法

方法说明
long getAndIncrement(int i)以原子方式将索引 i 的元素自增 1,并返回旧值
long incrementAndGet(int i)以原子方式将索引 i 的元素自增 1,并返回减少之后的值
long getAndDecrement(int i)以原子形式将索引i处的元素原子自减1,并返回旧值
long decrementAndGet(int i)以原子形式将索引i处的元素原子自减1,并返回减少之后的值
long addAndGet(int i, long delta)以原子形式将给定元素与数组中索引i的元素相加
long getAndSet(int i, long newValue)将地位i处的元素原子设置为给定值,并返回旧值
long get(int i)获取位置 i 的当前值
void lazySet(int i, long newValue)最终将位置 i 的元素设置为给定值
int length()返回数组的长度
void set(int i, long newValue)将位置 i 的元素设置为给定值
boolean compareAndSet(int i,int expect,int update)如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
boolean weakCompareAndSet(int i, int expect, long update)如果当前值 == 预期值,则以原子方式将位置 i 的元素设置为给定的更新值
long getAndUpdate(int i, LongUnaryOperator updateFunction)应用将给定函数利用以后值和给定值的原子更新以后值,返回旧值
long updateAndGet(int i, LongUnaryOperator updateFunction)应用将给定函数利用以后值和给定值的原子更新以后值,返回新值

 2.1.3、示例:

package com.example.test.java.juc;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.atomic.AtomicLongArray;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;@Slf4j(topic = "com.text.AtomicLongArray")
public class AtomicLongArrayTest {// 初始化 数组长度为 5private static AtomicLongArray arr = new AtomicLongArray(5);private static LongUnaryOperator longUnaryOperator = new LongUnaryOperator() {@Overridepublic long applyAsLong(long operand) {return operand + 10;}};private static LongBinaryOperator accumulatorFunction = new LongBinaryOperator() {@Overridepublic long applyAsLong(long left, long right) {return left + right;}};public static void main(String[] args) {for (int i = 0; i < arr.length(); i++) {log.debug("i-" + i + "=" + arr.get(i));}// 以原子形式给以后索引下标为(0)值加1,返回新值 (i++): 0log.debug("索引 0 incrementAndGet=" + arr.getAndIncrement(0));// 以原子形式给以后索引下标为(0)值加1,,返回新值(++i): 2log.debug("索引 0 incrementAndGet=" + arr.incrementAndGet(0));//以原子形式给以后索引下标为(0)值缩小 1,返回旧值 (i--):2log.debug("索引 0 incrementAndGet=" + arr.getAndDecrement(0));//以原子形式给以后索引下标为(0)值缩小 1,返回旧值 (--i):0log.debug("索引 0 incrementAndGet=" + arr.decrementAndGet(0));// 以原子形式将输出的数值与实例中的值(AtomicLongArray(0)里的value)相加,并返回后果 : 100log.debug("索引 0 addAndGet=" + arr.addAndGet(0, 100));// 获取 AtomicLongArray 的 value 100log.debug("索引 0 get=" + arr.get(0));log.debug("*********** JDK 1.8 ***********");//应用将给定函数利用给以后值和给定值的后果原子更新以后值,返回上一个值// 索引下标为 0 执行指定函数 后果为 100 + 10log.debug("索引 0 getAndUpdate=" + arr.updateAndGet(0, longUnaryOperator));// 索引下标为 1 执行指定函数 后果为 0 + 10log.debug("索引 1 getAndUpdate=" + arr.updateAndGet(1, longUnaryOperator));// 应用给定函数利用给指定下标和给定值的后果原子更新以后值,并返回后果 20log.debug("索引 1 accumulateAndGet=" + arr.accumulateAndGet(1, 10, accumulatorFunction));}
}

运行结果:

16:20:48.939 [main] DEBUG com.text.AtomicLongArray - i-0=0
16:20:48.945 [main] DEBUG com.text.AtomicLongArray - i-1=0
16:20:48.945 [main] DEBUG com.text.AtomicLongArray - i-2=0
16:20:48.945 [main] DEBUG com.text.AtomicLongArray - i-3=0
16:20:48.945 [main] DEBUG com.text.AtomicLongArray - i-4=0
16:20:48.945 [main] DEBUG com.text.AtomicLongArray - 索引 0 incrementAndGet=0
16:20:48.946 [main] DEBUG com.text.AtomicLongArray - 索引 0 incrementAndGet=2
16:20:48.946 [main] DEBUG com.text.AtomicLongArray - 索引 0 incrementAndGet=2
16:20:48.946 [main] DEBUG com.text.AtomicLongArray - 索引 0 incrementAndGet=0
16:20:48.946 [main] DEBUG com.text.AtomicLongArray - 索引 0 addAndGet=100
16:20:48.946 [main] DEBUG com.text.AtomicLongArray - 索引 0 get=100
16:20:48.946 [main] DEBUG com.text.AtomicLongArray - *********** JDK 1.8 ***********
16:20:48.946 [main] DEBUG com.text.AtomicLongArray - 索引 0 getAndUpdate=110
16:20:48.946 [main] DEBUG com.text.AtomicLongArray - 索引 1 getAndUpdate=10
16:20:48.947 [main] DEBUG com.text.AtomicLongArray - 索引 1 accumulateAndGet=20

2.2 AtomicReferenceArray介绍 

2.2.1、构造方法

方法名说明
AtomicReferenceArray(E[] array)

创建与给定数组具有相同长度的新 AtomicReferenceArray,并从给定数组复制其所有元素。

这个构造方法传入一个数组对象时,该数组对象必须是引用类型,int[]不可以,但是Integer[]的可以

AtomicReferenceArray(int length)

创建给定长度的新 AtomicReferenceArray。

为数组的每一位设置什么值是没有要求的,类似于Map的形式

2.2.2、方法

方法说明
boolean compareAndSet(int i, E expect, E update)如果当前值 == 预期值,则以原子方式将位置 i 的元素设置为给定的更新值
E get(int i)获取位置 i 的当前值
E getAndSet(int i, E newValue)以原子方式将位置 i 的元素设置为给定值,并返回旧值
void lazySet(int i, E newValue)最终将位置 i 的元素设置为给定值
int length()返回该数组的长度
void set(int i, E newValue)将位置 i 的元素设置为给定值
boolean weakCompareAndSet(int i, E expect, E update)如果当前值 == 预期值,则以原子方式将位置 i 的元素设置为给定的更新值

 2.2.3、代码示例

package com.example.test.java.juc;import java.util.concurrent.atomic.AtomicReferenceArray;public class AtomicReferenceArrayTest {public static void main(String[] args) {Long[] l = new Long[4];String[] s = new String[4];int[] i = new int[4];Integer[] in = new Integer[4];AtomicReferenceArray atomicReferenceArray = new AtomicReferenceArray(l);System.out.println(atomicReferenceArray.length());System.out.println(atomicReferenceArray.get(2));AtomicReferenceArray atomic = new AtomicReferenceArray(4);atomic.set(0,12);atomic.set(2,"Leefs");atomic.set(3,i);System.out.println(atomic.toString());}
}

运行结果:

4
null
[12, null, Leefs, [I@15327b79]

3、原子性测试 

        创建10个线程,每个线程分别对数组操作(自增)10000次(采用了函数式编程)。

package com.example.test.java.juc;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;public class AtomicArrayTest {/**参数1:提供数组、可以是线程不安全数组或线程安全数组参数2:获取数组长度的方法参数3:自增方法,回传 array, index参数4:打印数组的方法supplier 提供者 无中生有 ()->结果function 函数 一个参数一个结果 (参数)->结果,BiFunction (参数1,参数2)->结果consumer 消费者 一个参数没结果 (参数)->void,BiConsumer (参数1,参数2)->void*/private static <T> void demo(Supplier<T> arraySupplier,Function<T,Integer> lengthFun,BiConsumer<T,Integer> putConsumer,Consumer<T> printConsumer) {// 创建线程列表List<Thread> threadList = new ArrayList<>();// 得到数组返回的元素T array = arraySupplier.get();// 后面的Integer是返回结果int length = lengthFun.apply(array);// 根据数组长度来进行遍历,对值进行累加for (int i = 0; i < length; i++) {// 每个线程对数组作 10000 次操作threadList.add(new Thread(() -> {for (int j = 0; j < 10000; j++) {putConsumer.accept(array, j%length);}}));}threadList.forEach(t -> t.start()); // 启动所有线程threadList.forEach(t -> {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}});// 等所有线程结束printConsumer.accept(array);}public static void main(String[] args) {// 不安全数据demo(()->new int[10],(array)->array.length,(array, index) -> array[index]++,array-> System.out.println(Arrays.toString(array)));// 安全数据demo(()->new AtomicIntegerArray(10),(arr)-> arr.length(),(arr,index) -> arr.getAndIncrement(index),(arr)-> System.out.println(arr));}
}

运行结果:

[9035, 9053, 9034, 9049, 9039, 9041, 9032, 9027, 9040, 9025]
[10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000]

相关文章:

并发编程学习(十一):原子数组、

1、数组类型的原子类 原子数组类型&#xff0c;这个其实和AtomicInteger等类似&#xff0c;只不过在修改时需要指明数组下标。 CAS是按照来根据地址进行比较。数组比较地址&#xff0c;肯定是不行的&#xff0c;只能比较下标元素。而比较下标元素&#xff0c;就和元素的…...

递归到动态规划:省去枚举行为

如果在动态规划的过程中没有枚举行为&#xff0c;那严格位置依赖和傻缓存的方式并没有太大区别&#xff0c;但是当有枚举行为的时候&#xff08;一个位置依赖于多个位置&#xff09;&#xff0c;那严格位置依赖是有优化空间的&#xff0c;枚举行为也许可以省去&#xff0c;题目…...

服务(第二十一篇)mysql高级查询语句(二)

①视图表&#xff1a; 视图表是虚拟表&#xff0c;用来存储SQL语句的定义 如果视图表和原表的字段相同&#xff0c;是可以进行数据修改的&#xff1b; 如果两者的字段不通&#xff0c;不可以修改数据。 语法&#xff1a; 创建&#xff1a;create view 试图表名 as ... 查…...

MYSQL高可用配置(MHA)

1、什么是MHA MHA&#xff08;Master High Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现就是解决MySQL 单点的问题。 MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作。 MHA能在故障切换的过程中最大…...

单精度浮点数与十进制数据相互转换

一、float基础&#xff1a; Float类型占4个字节,也就是32bit,其中最高位是符号位,2~9位是指数位,后边的23bit是数值位.如下所示 大部分数据的二进制形式都可以用科学计数法表示,即1.m*2^n这种形式,只要知道m和n,就能确定一个数值 二、小数位如何转变为二进制&#xff1a; 下面…...

PMP敏捷-4大价值观、12原则

宣言及4大价值观 个体及互动 胜于 流程和工具 以人为本 工作的软件 胜于 完整的文档 以价值为导向 客户合作 胜于 合同谈判 合作共赢 应对变更 胜于 遵循计划 拥抱变化 12原则 工作原则&#xff1a;精益、至简&#xff0c;实现这种原则的方式是“定期反省”。9、10、12 …...

K8S—Helm

一、Helm介绍 helm通过打包的方式&#xff0c;支持发布的版本管理和控制&#xff0c;很大程度上简化了Kubernetes应用的部署和管理。 Helm本质就是让k8s的应用管理&#xff08;Deployment、Service等&#xff09;可配置&#xff0c;能动态生成。通过动态生成K8S资源清单文件&a…...

ALSA内部函数调用流程

ALSA内部函数调用流程 一直都有这样的一个疑问 就是在linux系统中我们调用snd_pcm_open后&#xff0c;就不知道alsa内部是怎么运行的了 用户的pcm_open()相当于先对ASoC各个驱动模块startup()&#xff0c;再做hw_params()。 pcm_open()pcm->fd open("/dev/snd/pcm…...

Python正则表达式详解,保姆式教学,0基础也能掌握正则

正则作为处理字符串的一个实用工具&#xff0c;在Python中经常会用到&#xff0c;比如爬虫爬取数据时常用正则来检索字符串等等。正则表达式已经内嵌在Python中&#xff0c;通过导入re模块就可以使用&#xff0c;作为刚学Python的新手大多数都听说”正则“这个术语。 今天来给…...

ChatGPT 接入飞书教程,创建自己的聊天机器人

ChatGPT 接入飞书教程,创建自己的聊天机器人 一、飞书进入开发者平台。点击创建应用。二、打开Aircode,点击创建应用,上面输入名字,下面选择Node.js v16三、配置环境,点击Environments,创建四个变量,全部要大写本教程收集于: AIGC从入门到精通教程 首先,准备三个账号…...

JS生成随机数(多种解决方案)

JS生成随机数 概述 随机数是编程语言中的重要组成部分。在JavaScript中&#xff0c;生成随机数是一项简单的任务。本文将介绍生成随机数的各种方法。 Math.random() Math.random()是JavaScript中生成随机数最常见的方法。该方法返回介于0和1之间的随机数。例如&#xff0c;…...

文件IO 函数 静态库和动态库的创建 5.11

5.11 文件IO函数 1.数据读写 ssize_t read(int fd,void *buf,size_t count); 功能&#xff1a; ​ 从fd对应的文件中 读取前count个字节的数据到buf缓冲区中 头文件&#xff1a; ​ #include <unistd.h> 参数&#xff1a; ​ fd &#xff1a;文件描述符 ​ buf…...

考研日语-详解ている、てある、ていく、てくる用法

目录 一、ている用法 1. 表示现在状态 2. 表示持续动作 3. 表示经验或习惯 4. 表示结果或效果 二、てある用法 1. 表示已经完成的动作 2. 表示现在状态 3. 表示被动 三、ていく用法 1. 表示未来的动作 2. 表示逐渐变化的过程 四、てくる用法 1. 表示过去到现在的…...

Spring Security 6.x 系列【36】授权服务器篇之OpenID Connect 1.0

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.0.4 本系列Spring Security 版本 6.0.2 本系列Spring Authorization Server 版本 1.0.2 源码地址:https://gitee.com/pearl-organization/study-spring-security-demo 文章目录 1. 前言2. OpenID Connect…...

【计算机视觉 | Pytorch】timm 包的具体介绍和图像分类案例(含源代码)

一、具体介绍 timm 是一个 PyTorch 原生实现的计算机视觉模型库。它提供了预训练模型和各种网络组件&#xff0c;可以用于各种计算机视觉任务&#xff0c;例如图像分类、物体检测、语义分割等等。 timm 的特点如下&#xff1a; PyTorch 原生实现&#xff1a;timm 的实现方式…...

轻博客Plume的搭建

什么是 Plume &#xff1f; Plume 是一个基于 ActivityPub 的联合博客引擎。它是用 Rust 编写的&#xff0c;带有 Rocket 框架&#xff0c;以及 Diesel 与数据库交互。前端使用 Ructe模板、WASM 和SCSS。 反向代理 假设我们实际访问地址为&#xff1a; https://plume.laosu.ml…...

机器人关节电机PWM

脉冲宽度调制(Pulse width modulation,PWM)技术。一种模拟控制方式 机器人关节电机的控制通常使用PWM(脉冲宽度调制)技术。PWM是一种用于控制电子设备的技术,通过控制高电平和低电平之间的时间比例,实现对电子设备的控制。在机器人关节电机中,PWM信号可以控制电机的…...

MPU6050详解(含源码)

前言&#xff1a;MPU6050是一款强大的六轴传感器&#xff0c;需要理解MPU6050首先得有IIC的基础&#xff0c;MPU6050 内部整合了 3 轴陀螺仪和 3 轴加速度传感器&#xff0c;并且含有一个第二 IIC 接口&#xff0c;可用于连接外部磁力传感器&#xff0c;内部有硬件算法支持. 1…...

Vue入门学习笔记:TodoList(三):实例中的数据、事件和方法

目录&#xff1a; Vue入门学习笔记&#xff1a;TodoList&#xff08;一&#xff09;&#xff1a;HelloWorld Vue入门学习笔记&#xff1a;TodoList&#xff08;二&#xff09;&#xff1a;挂载点、模板、实例 Vue入门学习笔记&#xff1a;TodoList&#xff08;三&#xff09;&a…...

怎么找到引发回流的JavaScript代码?

要找到引发回流的JavaScript代码&#xff0c;可以使用浏览器的开发者工具中的性能分析器。不同的浏览器有不同的名称和位置&#xff0c;例如Google Chrome的开发者工具中的性能分析器被称为Performance&#xff0c;Firefox的开发者工具中的性能分析器被称为Profiler。 以下是在…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

《Offer来了:Java面试核心知识点精讲》大纲

文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...

Java数组Arrays操作全攻略

Arrays类的概述 Java中的Arrays类位于java.util包中&#xff0c;提供了一系列静态方法用于操作数组&#xff08;如排序、搜索、填充、比较等&#xff09;。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序&#xff08;sort&#xff09; 对数组进行升序…...