原子操作类(持续更新,未完结)

在这里插入图片描述

目录

  • 基本类型原子类
  • 数组类型原子类
  • 引用类型原子类
  • 对象的属性修改原子类
  • 原子操作增强类
    • LongAdder 高性能原理说明
    • LongAdder源码深度解析
    • LongAdder小总结
  • 相关文献

在这里插入图片描述

分组来给大家讲解相关原子类的常用api使用,不会全部都讲完,只是抽取几个比较经典的讲一下案例使用

基本类型原子类

  • AtomicInteger
  • AtomicBoolean
  • AtomicLong

问题案例:为什么结果是不准呢,因为里面的50个线程还没有跑完,main线程去拿结果,就会导致没有计算完拿到了错误结果
在这里插入图片描述
要等前面50个线程跑完,让main线程sleep一段时间也可以,但是不太好,怎么解决呢?
在这里插入图片描述
countDownLatch,50个线程,等到50个线程都跑完,后面的线程拿到最终值

数组类型原子类

  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray

案例演示:数组根据下标获取数值
在这里插入图片描述

引用类型原子类

  • AtomicReference
  • AtomicStampedReference(利用版本号,解决ABA问题,能够知道修改了几次)
  • AtomicMarkableReference(将状态戳简化为true/false,解决是否修改过)

案例演示:同时间不同线程拿到的都是false初始化值,但是a线程执行完之后,发生了改变,b线程再去修改时,发现值被使用过,再次修改失败
在这里插入图片描述

对象的属性修改原子类

  • AtomicLongFieldUpdater
  • AtomicIntegerFieldUpdater
  • AtomicReferenceFieldUpdater

作用:以一种线程安全的方式操作非线程安全对象内的某些字段

不用原子操作类以前:效果虽然能实现,但是加了synchronized
在这里插入图片描述

现在不加锁,针对引用类的字段进行原子性操作:效果也一致
在这里插入图片描述

上面是针对integer,那么引用类中的字段呢?来,让我们接着奏乐接着舞

AtomicReferenceFieldUpdater:基于反射的实用程序,可以对指定类的指定volatile引用字段进行原子更新。

需求:多线程并发调用一个类的初始化方法,如果未被初始化,将执行初始化工作,要求只能被初始化一次,只有一个线程操作成功

案例实现如下:
在这里插入图片描述

原子操作增强类

  • DoubleAccumulator
  • DoubleAdder
  • LongAccumulator
  • LongAdder

这几个是java8出来的增强类,前面十二个是java5的原子操作类
在这里插入图片描述
按照以上图片红框内容,我们来实现一个热点商品点赞数,点赞累加统计,要求吞吐量极高,不要求实时精准的(98%)需求(因为正在统计时,也在实时增加点赞数)

单线程简单使用:
在这里插入图片描述
以上案例可以总结出:LongAdder支持简单的加法计算,计算初始量从0开始,而LongAccumulator支持自定义计算公式,且初始值也可以自定义

多线程案例:50个线程,每个线程100w次,统计总点赞数

内部类:

class ClickNumber{int number = 0;public synchronized void clickSynchronized(){number++;}AtomicLong atomicLong = new AtomicLong(0);public void clickAtomicLong(){atomicLong.incrementAndGet();}LongAdder longAdder = new LongAdder();public void clickLongAdder(){longAdder.increment();}LongAccumulator longAccumulator = new LongAccumulator((x,y)->x+y,0);public void clickLongAccumulator(){longAccumulator.accumulate(1);}
}

实现类:

public static final int _1w = 10000;public static final int threadNumber = 50;public static void main(String[] args) throws InterruptedException {ClickNumber clickNumber = new ClickNumber();long startTime;long endTime;final CountDownLatch countDownLatch1 = new CountDownLatch(threadNumber);final CountDownLatch countDownLatch2 = new CountDownLatch(threadNumber);final CountDownLatch countDownLatch3 = new CountDownLatch(threadNumber);final CountDownLatch countDownLatch4 = new CountDownLatch(threadNumber);startTime = System.currentTimeMillis();for (int i = 0; i < threadNumber; i++) {new Thread(()->{try {for (int j = 1; j <= 100 * _1w; j++) {clickNumber.clickSynchronized();}} finally {countDownLatch1.countDown();}},String.valueOf(i)).start();}countDownLatch1.await();endTime = System.currentTimeMillis();System.out.println("耗时:"+(endTime-startTime)+"毫秒 \t clickSynchronized:"+clickNumber.number);startTime = System.currentTimeMillis();for (int i = 0; i < threadNumber; i++) {new Thread(()->{try {for (int j = 1; j <= 100 * _1w; j++) {clickNumber.clickAtomicLong();}} finally {countDownLatch2.countDown();}},String.valueOf(i)).start();}countDownLatch2.await();endTime = System.currentTimeMillis();System.out.println("耗时:"+(endTime-startTime)+"毫秒 \t clickAtomicLong:"+clickNumber.atomicLong.get());startTime = System.currentTimeMillis();for (int i = 0; i < threadNumber; i++) {new Thread(()->{try {for (int j = 1; j <= 100 * _1w; j++) {clickNumber.clickLongAdder();}} finally {countDownLatch3.countDown();}},String.valueOf(i)).start();}countDownLatch3.await();endTime = System.currentTimeMillis();System.out.println("耗时:"+(endTime-startTime)+"毫秒 \t clickLongAdder:"+clickNumber.longAdder.sum());startTime = System.currentTimeMillis();for (int i = 0; i < threadNumber; i++) {new Thread(()->{try {for (int j = 1; j <= 100 * _1w; j++) {clickNumber.clickLongAccumulator();}} finally {countDownLatch4.countDown();}},String.valueOf(i)).start();}countDownLatch4.await();endTime = System.currentTimeMillis();System.out.println("耗时:"+(endTime-startTime)+"毫秒 \t clickLongAccumulator:"+clickNumber.longAccumulator.get());}

效果图:
在这里插入图片描述
从效果图中看,LongAdder高并发大数据量下性能比AtomicLong好10倍

那么为什么LongAdder能那么快呢?

LongAdder 高性能原理说明

AtomicLong是通过CAS自旋保证原子性,高并发大数量的情况下,也是一个个执行,所以性能不佳

LongAdder底层有base跟cell理念设计,在低并发情况下,跟AtomicLong性质一样,通过本身base的CAS自旋处理,但是高并发情况下,base一个肯定忙不过来,就启用cell扩容,开启多个窗口cell[0]、cell[1]、cell[…],利用base+cell达到分散热点的作用,如果要获取真正的long值,结果就是base+cell数组

而以上LongAdder设计思想是通过Striped64这个类落地实现的,LongAdder是Striped64的子类
在这里插入图片描述
LongAdder性能那么好主要原因是Striped64,这是Striped64类的一些变量或参数定义,其中最重要的就是NCPU、cells、base、cellsBusy

  • NCPU:当前计算机CPU数量,即cells数组的最大长度,Cell数组扩容时会使用到
  • cells:cell数组,为二次方的扩容,2、4、8…
  • base:类似于AtomicLong中全局的value值。在没有竟争情况下数据直接累加到base上,或者cells扩容时,也需要将数据写入到base上
  • cellsBusy:初始化cells或者扩容cells需要获取锁,0:表示无锁状态 1:表示其他线程已经持有了锁
  • collide:表示扩容意向,false一定不会扩容,true可能会扩容
  • casCelsBusy():通过CAS操作修改cellsBusy的值,CAS成功代表获取锁,返回true
  • getRrobe():获取当前线程的hash值
  • advanceProbe():重置当前线程的hash值

LongAdder源码深度解析

源码分析按照以下链路来看,其中longAccumulate是重点
LongAdder.increment()->
LongAdder.add()->
Striped64.longAccumulate()->
LongAdder.sum()

在这里插入图片描述

。。。。。此节点未完结,后面继续补坑,小编被同事背刺了,很无语

LongAdder小总结

AtomicLong:线程安全,可允许一些性能损耗,要求高精度时可使用,保证精度,性能代价;是多个线程针对单个热点值value进行原子操作

原理:CAS+自旋(incrementAndGet)
场景:低并发下的全局计算,Atomicong能保证并发情况下计数的准确性,其内部通过CAS来解决并发安全性的问题。
缺陷:高并发后性能急剧下降,为什么?因为AtomicLong的自旋会成为瓶颈,高并发后造成大量cpu空转

LongAdder:当需要在高并发下有较好的性能表现,且对值的精确度要求不高时,可以使用,保证性能,用精度付出代价;是每个线程拥有自己的槽,各个线程一般只对自己槽中的那个值进行CAS操作

原理:CAS+Base+Cell数组分散,空间换时间并分散了热点数据
场景:高并发下的全局计算
缺陷:sum求和后还有计算线程修改结果的话,最后结果不够准确

相关文献

jdk api文档:https://www.runoob.com/manual/jdk11api/java.base/java/util/concurrent/atomic/package-summary.html

就先说到这 \color{#008B8B}{ 就先说到这} 就先说到这
在下 A p o l l o \color{#008B8B}{在下Apollo} 在下Apollo
一个爱分享 J a v a 、生活的小人物, \color{#008B8B}{一个爱分享Java、生活的小人物,} 一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞! \color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!} 咱们来日方长,有缘江湖再见,告辞!

在这里插入图片描述

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

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

相关文章

c++树(三)重心

目录 重心的基础概念 定义&#xff1a;使最大子树大小最小的点叫做树的重心 树的重心求解方式 例题&#xff1a; 重心的性质 性质1&#xff1a;重心点的最大子树大小不大于整棵树大小的一半。 性质1证明&#xff1a; 性质1的常用推导 推导1&#xff1a; 推导2&#x…

AI绘画SD中 ControlNet 组件 IP-Adapter 实现风格迁移,AI绘画垫图神器!

大家好&#xff0c;我是画画的小强 今天给大家介绍一下AI绘画SD中ControlNet 的 IP-Adapter 组件&#xff0c;该组件可以方便快捷的帮我们对图片的风格进行迁移&#xff0c;简而言之就是可以参考你放置的图片风格来生成其他图片。 它的效果和reference only有点类似&#xff…

了解网络是如何运作

“Web 的工作原理”提供了一个简化的视图,用于了解在计算机或手机上的 Web 浏览器中查看网页时发生的情况。 这个理论对于短期内编写 Web 代码来说并不是必需的,但不久之后,你就会真正开始从理解后台发生的事情中受益。 客户端和服务器 连接到 Internet 的计算机称为客户端和…

四、面向对象2(30小时精通C++和外挂实战)

四、面向对象2&#xff08;30小时精通C和外挂实战&#xff09; B-01-对象的内存B-02-构造函数B-04-成员变量的初始化B-05-析构函数B-06-内存管理B-07-类的声明和实现分离B-08-命名空间B-09-继承B-10-成员访问权限 B-01-对象的内存 在C中对象可以自由的放在3中地方&#xff0c;而…

【算法】插入排序 与 希尔排序 概念+图解+代码【Python C C++】

1.插入排序 1.1概念 插入排序(InsertionSort)&#xff0c;一般也被称为直接插入排序。 对于少量元素的排序&#xff0c;它是一个有效的算法。插入排序是一种最简单的排序方法&#xff0c;它的基本思想是将一个元素插入到已经排好序的有序表中&#xff0c;从而构造出一个新的…

mathtype7.4永久激活码(mathtype7永久注册码网盘下载)

大家好&#xff0c;我是你们的数学小能手&#xff01;今天我要安利一款超实用的工具——MathType&#xff0c;让你在数学的世界里游刃有余&#xff0c;轻松搞定各种公式和计算。准备好被种草了吗&#xff1f;跟我一起来瞧瞧吧&#xff01; MathType是理科生专用的必备工具&…

EXCEL 排名(RANK,COUNTIFS)

1.单列排序 需求描述&#xff1a;如有下面表格&#xff0c;需要按笔试成绩整体排名。 解决步骤&#xff1a; 我们使用RANK函数即可实现单列整体排名。 Number 选择第一列。 Ref 选择这一整列&#xff08;CtrlShift向下箭头、再按F4&#xff09;。 "确定"即可计算…

一键解锁百变发型!上交联合Tiamat震撼发布Stable-Hair发型移植黑科技!

Stable-Hair 是一种基于扩散的新型发型转移方法&#xff0c;可以稳健地转移各种现实世界的发型。在各种具有挑战性的发型上实现了高度详细和高保真度的转移&#xff0c;效果令人印象深刻&#xff0c;同时保留了原始身份内容和结构。 相关链接 论文链接: https://arxiv.org/pdf…

案例实践 | 基于长安链的福建省气象综合治理区块链平台

案例名称-【福建省气象综合治理区块链平台】 ■ 实施单位 福建福链科技有限公司 ■ 业主单位 福建省气象信息中心 ■ 上线时间 2023年10月 ■ 用户群体 福建省气象、防灾减灾相关单位 ■ 用户规模 全省2100余个气象站、气象局以及防灾减灾部门 案例背景与解决痛点 …

跟代码执行流程,读Megatron源码(四)megatron初始化脚本initialize.py之initialize_megatron()分布式环境初始化

在前文中&#xff0c;我们讲述了pretrain函数的执行流程&#xff0c;其首要步骤是megatron分组的初始化与环境的配置。本文将深入initialize_megatron函数源码&#xff0c;剖析其初始化分布式训练环境的内部机制。 注&#xff1a;在此假设读者具备3D并行相关知识 一. initiali…

【MARL】MADDPG + attention 实现(+论文解读)

文章目录 前言注意力机制论文里的attention回顾知识-MADDPG讲解1.Q的定义2.Q的恒等式3.论文里的attention4.好处 实现 和 修改结果展示原论文代码 翻改版修改后原maddpg代码 前言 导师让在MADDPG上加一个注意力机制&#xff0c;试了很多种&#xff0c;下面的参考的论文的效果最…

C++——保持原有库头文件不变的情况下,成功编译运行工程

问&#xff1a;想要保持原来库方式&#xff0c;应该怎么操作呢&#xff1f; 答&#xff1a;如果想保持原来的方式&#xff0c;则只需要将 库所在路径 tracker/detector/rknn_model_zoo/utils 加入到 工程库包含中即可。

基于jeecgboot-vue3的Flowable流程-自定义业务表单流程历史信息显示

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、对于自定义业务表单的流程历史记录信息做了调整&#xff0c;增加显示自定义业务表单 <el-tab-pane label"表单信息" name"form"><div v-if"customF…

ESP32开发进阶:OLED屏幕显示旋转的3D模型

一、硬件接线 我选择的是最常见的一块板子&#xff1a;ESP-WROOM-32&#xff0c;硬件接线如下&#xff1a; 21 - SDA 22 - SCL 二、Arduino端代码 我们使用Arduino和Adafruit SSD1306库在OLED显示屏上绘制和旋转一个3D立方体。 首先&#xff0c;定义立方体顶点和…

CSS(七)——CSS 列表和CSS Table(表格)

目录 CSS 列表 列表 作为列表项标记的图像 列表 - 简写属性 移除默认设置 所有的CSS列表属性 CSS 表格 表格边框 折叠边框&#xff08;border-collapse&#xff09; 表格宽度和高度 表格文字对齐 表格填充 表格颜色 CSS 列表 CSS 列表属性作用如下&#xff1a; 设…

C#开发的全屏图片切换效果应用 - 开源研究系列文章 - 个人小作品

这天无聊&#xff0c;想到上次开发的图片显示软件《 PhotoNet看图软件 》&#xff0c;然后想到开发一个全屏图片切换效果的应用&#xff0c;类似于屏幕保护程序&#xff0c;于是就写了此博文。这个应用比较简单&#xff0c;主要是全屏切换换图片效果的问题。 1、 项目目录&…

【Vue3】watch 监视 ref 定义的数据

【Vue3】watch 监视 ref 定义的数据 背景简介开发环境开发步骤及源码参数说明 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努…

【C++进阶学习】第八弹——红黑树的原理与实现——探讨树形结构存储的最优解

二叉搜索树&#xff1a;【C进阶学习】第五弹——二叉搜索树——二叉树进阶及set和map的铺垫-CSDN博客 AVL树&#xff1a; ​​​​​​【C进阶学习】第七弹——AVL树——树形结构存储数据的经典模块-CSDN博客 前言&#xff1a; 在前面&#xff0c;我们已经学习了二叉搜索树和…

PCIe 6.0为什么需要14-bit tag

1.TLP中的tag是什么 在PCIe TLP&#xff08;Transaction Layer Packet&#xff09;中&#xff0c;tag是分配给特定Non-Posted Request的编号&#xff0c;协议要求CPL/CPLD中的tag 与对应non-post request TLP中的tag保持一致&#xff0c;因此Requester可以使用tag来识别CPL…

免费【2024】springboot 趵突泉景区的智慧导游小程序

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…