JUC:原子类型的使用(原子整数、原子引用、原子数组、字段更新器、累加器)

文章目录

  • 原子类型
    • AtomicInteger 原子整数
    • AtomicReferenc 原子引用
    • AtomicStampedReference 带版本号的原子引用
    • AtomicMarkableReference 仅记录是否修改的原子引用
    • AtomicXXXArray 原子数组
    • AtomicXXXFieldUpdater 字段更新器
    • LongAdder累加器

原子类型

AtomicInteger 原子整数

public class test6 {public static void main(String[] args) {AtomicInteger i = new AtomicInteger();System.out.println(i.getAndIncrement()); // i++ sout: 0System.out.println(i.incrementAndGet()); // ++i sout: 2System.out.println(i.decrementAndGet()); // --i sout: 1System.out.println(i.getAndDecrement()); // i-- sout: 1// i = 0System.out.println(i.getAndAdd(5)); // sout:0 i += 5System.out.println(i.addAndGet(-5)); // i -= 5 sout:0// i = 0System.out.println(i.getAndUpdate(p -> p - 2)); // sout:0 p -= 2System.out.println(i.updateAndGet(p -> p + 2)); // p += 2 sout: 0}
}

在这里插入图片描述

AtomicReferenc 原子引用

class DecimalAccountSafeCas{AtomicReference<BigDecimal> ref;public DecimalAccountSafeCas(BigDecimal balance) {ref = new AtomicReference<>(balance);}public BigDecimal getBalance() {return ref.get();}public void withdraw(BigDecimal amount) {while (true) {BigDecimal prev = ref.get();BigDecimal next = prev.subtract(amount); // 减小if (ref.compareAndSet(prev, next)) { // casbreak;}}}
}

AtomicStampedReference 带版本号的原子引用

解决aba问题,aba问题之前介绍过了。
如果版本号与之前获取的相同,那么就进行交换,同时更新版本号。
可以知道更改次数。

class DecimalAccountSafeCas{AtomicStampedReference<BigDecimal> ref;public DecimalAccountSafeCas(BigDecimal balance) {ref = new AtomicStampedReference<>(balance, 0); // 初始版本号0}public BigDecimal getBalance() {return ref.getReference();}public void withdraw(BigDecimal amount) {while (true) {BigDecimal prev = ref.getReference();int stamp = ref.getStamp();// 获取版本号// 如果这之中有其他线程又修改了ref,那么版本号改变与之前不同。就会cas失败    BigDecimal next = prev.subtract(amount); // 减小if (ref.compareAndSet(prev, next, stamp, stamp + 1)) { // cas。版本号相同才交换,并且更新版本号break;}}}
}

AtomicMarkableReference 仅记录是否修改的原子引用

我们一般不关心中间修改了多少次,我么只在乎是否修改过,那么就可以用这个类。

所以一个boolean值就可以记录。

class DecimalAccountSafeCas{AtomicMarkableReference<BigDecimal> ref;public DecimalAccountSafeCas(BigDecimal balance) {ref = new AtomicMarkableReference<>(balance, true);}public BigDecimal getBalance() {return ref.getReference();}public void withdraw(BigDecimal amount) {while (true) {BigDecimal prev = ref.getReference();BigDecimal next = prev.subtract(amount); // 减小// 如果这时有线程修改,把mark变为了false,那么就会cas就会失败// 因为只有true,和false,我们就直接就对比是否是true就行了,不用在获取if (ref.compareAndSet(prev, next, true, false)) { // cas。版本号相同才交换,并且更新版本号break;}}}
}

AtomicXXXArray 原子数组

我么一般都不是修改引用指向,而是引用里的内容,就比如数组。

下面是线程安全的数组。

  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray

这里我么先用普通数组,来看看是否有线程安全问题:

package com.leran;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;public class test7 {public static void main(String[] args) {demo(() -> new int[10],(array) ->  array.length,(array, idx) -> array[idx]++,array -> System.out.println(Arrays.toString(array)));}private static <T> void demo(Supplier<T> arraySupplier, // 生产者,无中生有Function<T, Integer> lengthFun, // 一个参数一个结果 BiFunction 多个参数,多个结果BiConsumer<T, Integer> putConsumer, // 消费者多个参数,无结果Consumer<T> printConsumer ) { // 一个参数,无结果List<Thread> ts = new ArrayList<>();T array = arraySupplier.get(); // 获取传入的数组int length = lengthFun.apply(array); // 获取长array长度for (int i = 0; i < length; i++) {// 每个线程对数组作 10000 次操作ts.add(new Thread(() -> {for (int j = 0; j < 10000; j++) {putConsumer.accept(array, j%length);}}));}ts.forEach(t -> t.start()); // 启动所有线程ts.forEach(t -> {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}}); // 等所有线程执行完,输出printConsumer.accept(array);}
}

在这里插入图片描述

显然是不安全的,下面介绍安全的AtomicIntegerArray。

demo方法不变,改变传入的数组。

    demo(() -> new AtomicIntegerArray(10),(array) ->  array.length(),(array, idx) -> array.getAndIncrement(idx),array -> System.out.println(array));

在这里插入图片描述

其他用法相似。

AtomicXXXFieldUpdater 字段更新器

用于更新某一类中的属性。

  • AtomicReferenceFieldUpdater // 域字段
  • AtomicIntegerFieldUpdater
  • AtomicLongFieldUpdater

必须配合volatile使用。

如:AtomicIntegerFieldUpdater

public class test8 {public static void main(String[] args) {AtomicIntegerFieldUpdater fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(Student.class, "age");Student student = new Student();fieldUpdater.compareAndSet(student, 0, 5);System.out.println(student.age); // 5fieldUpdater.compareAndSet(student,5, 10);System.out.println(student.age); // 10fieldUpdater.compareAndSet(student, 5, 20); // 修改失败System.out.println(student.age); // 10}
}class Student{volatile int age;@Overridepublic String toString() {return "student{" +"age=" + age +'}';}
}

在这里插入图片描述

其他用法相似。

LongAdder累加器

java中专门用于累加的,所以性能肯定比我么AtomicLong好。
下面是对比。

public class test9 {public static void main(String[] args) {for (int i = 0; i < 5; i++) {demo(() -> new AtomicLong(), adder -> adder.getAndIncrement());}for (int i = 0; i < 5; i++) {demo(() -> new LongAdder(), adder -> adder.increment());}}private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) {T adder = adderSupplier.get();long start = System.nanoTime();List<Thread> ts = new ArrayList<>();for (int i = 0; i < 40; i++) {ts.add(new Thread(() -> {for (int j = 0; j < 500000; j++) {action.accept(adder);}}));}ts.forEach(t -> t.start());ts.forEach(t -> {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}});long end = System.nanoTime();System.out.println(adder + " cost:" + (end - start)/1000_000 + "ns");}
}

前五次是AtomicLong累加
后五次是LongAdder累加

20000000 cost:414ns
20000000 cost:390ns
20000000 cost:366ns
20000000 cost:377ns
20000000 cost:414ns
20000000 cost:33ns
20000000 cost:26ns
20000000 cost:26ns
20000000 cost:27ns
20000000 cost:37nsProcess finished with exit code 0

显然是快了10倍左右。

性能提升的原因,就是在有竞争时,设置多个累加单元Cell,最后将结果汇总。
这样在累加时操作的是不同的 Cell 变量,因此减少了 CAS 重试失败,从而提高性能。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

部署项目遇到的各种问题总结

文章目录 前言一、后端问题 jar包运行出现错误宝塔面板使用jdk17二、数据库问题 版本问题三、前端问题 连不上后端总结 前言 在做完项目之后&#xff0c;为了让别人访问到自己的网站&#xff0c;就需要部署前端后端以及数据库&#xff0c;但是在部署的过程中出现了各种问题和困…

vue-quill-editor 富文本编辑器(可上传视频图片),组件挂载的方式实现

1.安装 npm install vue-quill-editor --save npm install quill-image-drop-module --save npm install quill-image-resize-module --save2.在组件下面新增组件 QlEditor (1)index.vue <template><div><div idquillEditorQiniu><!-- 基于element…

如何制作不同类型的二维码?快捷在线生码的3个步骤

怎么简单快速的完成二维码制作呢&#xff1f;现在二维码可以做很多的用途使用&#xff0c;比如可以用于内容展示、下载文件、播放音视频、扫码看图等等。那么上面讲述的这些类型二维码该如何制作呢&#xff0c;相信有很多的小伙伴都会二维码制作的技巧非常感兴趣。那么下面就让…

【Redis基础篇】详细讲解Redis

这篇文章让你详细了解Redis的相关知识&#xff0c;有代码讲解以及图片剖析&#xff0c;让你更轻松掌握 制作不易&#xff0c;感觉不错&#xff0c;请点赞收藏哟 &#xff01;&#xff01;&#xff01; 目录 1 redis基础 1.1 定义 1.2 SQL和NOSQL不同点 1.3 特征 1.4 Redis…

门户系统商城模块

商城系统&#xff1a;快递商品本地团购到店核销购物场景全覆盖&#xff0c;全新商销解决方案 商城系统是指一套用于构建和运营电商平台的软件系统&#xff0c;可以帮助企业快速搭建网上商城&#xff0c;实现商品销售、订单管理、客户服务等功能。 商城系统的功能&#xff1a;…

基于多数据源融合的医疗知识图谱框架构建研究

基于多数据源融合的医疗知识图谱框架构建研究 提出背景医学数据源医学数据获取方法知识图谱的构建 提出背景 论文&#xff1a;基于多数据源融合的医疗知识图谱框架构建研究 本文以医疗领域的实际应用需求为出发点&#xff0c;从医疗大数据获取、医疗实体及关系标注、医疗实体…

Linux-3 yum和vim

目录 本节目标&#xff1a; Linux 软件包管理器 yum 什么是软件包 1.yum是什么&#xff1f;软件包&#xff1f; 2.Linux(centos)的生态 3.yum的相关操作 我怎么知道我应该安装什么软件&#xff1f; 4.yum的本地配置 关于 rzsz 查看软件包 Linux编辑器-vim使用 1.v…

状态压缩DP

哈密顿路径问题&#xff1a; 一般设 表示 状态下&#xff0c;为最后一个最值情况 。 一般有两种稍微不同的写法&#xff0c;单纯就是写法不同&#xff0c;思路方法都相同。 第一个例题为第一种转移方法&#xff0c;有当前转移后面。 后面的都是由前面转移目前。 G. Shuff…

苹果IPA上传技巧:优化应用提交流程,提高通过率

目录 引言 摘要 第二步&#xff1a;打开appuploader工具 第二步&#xff1a;打开appuploader工具&#xff0c;第二步&#xff1a;打开appuploader工具 第五步&#xff1a;交付应用程序&#xff0c;在iTunes Connect中查看应用程序 总结 引言 在将应用程序上架到苹果应用商…

阿里云未来20%代码由AI编写;支付宝开放「AI 就医助理」

阿里云未来 20% 代码由通义灵码编写 阿里云于 4 月 2 日开始&#xff0c;在内部全面推行 AI 编程&#xff0c;使用通义灵码辅助程序员写代码、读代码、查 BUG、优化代码等。阿里云此次还专门给通义灵码分配了一个正式的员工工号—— AI001 。 有阿里云相关人士表示&#xff0c…

在电脑上怎么把视频做成二维码?视频生码的方法及步骤

在电脑上怎么把视频做成二维码呢&#xff1f;现在将视频存入二维码之后&#xff0c;将二维码分享或者打印出来&#xff0c;用这种方式来分享或者传递视频对比传统方式会更加的方便快捷。无需占用接收者的内存&#xff0c;手机扫码调取云端储存的视频&#xff0c;消耗视频流量来…

Flink 流批一体在模型特征场景的使用

摘要&#xff1a;本文整理自B站资深开发工程师张杨老师在 Flink Forward Asia 2023 中 AI 特征工程专场的分享。内容主要为以下四部分&#xff1a; 模型特征场景流批一体性能优化未来展望 一、 模型特征场景 以下是一个非常简化并且典型的线上实时特征和样本的生产过程。 前面…