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

在这里插入图片描述

目录

  • 基本类型原子类
  • 数组类型原子类
  • 引用类型原子类
  • 对象的属性修改原子类
  • 原子操作增强类
    • 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,一经查实,立即删除!

相关文章

stable diffusion文生图代码解读

使用diffusers运行stable diffusion&#xff0c;文生图过程代码解读。 只按照下面这种最简单的运行代码&#xff0c;省略了一些参数的处理步骤。 from diffusers import DiffusionPipeline pipeline DiffusionPipeline.from_pretrained(MODEL_PATH , torch_dtypetorch.float1…

openjdk导出文件时报空指针异常--casesby 字体

参考链接&#xff1a; https://blog.adoptopenjdk.net/2021/01/prerequisites-for-font-support-in-adoptopenjdk/ http://www.shadow-li.com.cn/alpine-jdk-font-null/ 报错信息 stackTrace : "cn.afterturn.easypoi.exception.excel.ExcelExportException: Excel导出错…

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;而…

Oracle 19c 修改db_name

将db_namedcpfarei 修改成 db_namedcpfardb&#xff0c;使用oracle自带的nid工具修改 修改前&#xff1a; SQL> show parameter nameNAME TYPE VALUE ------------------------------------ ----------- ------------------------…

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

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

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

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

鸿蒙9+在TV端焦点封装控制

鸿蒙9 目前不支持鸿蒙系统电视&#xff0c;但是往后肯定是必须会支持的&#xff0c;所以直接学arkts就完事了&#xff0c;目前的api9对焦点控制还是不够直接简洁&#xff0c;估计还在完善中&#xff0c;但是可以通过自定义component来实现一下 首先踩坑&#xff1a; Row官方说…

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…

【SpringBoot】URL映射之consumes和produces匹配、params和header匹配

4.2.3 consumes和produces匹配 //处理request Content-Type为"application/json"类型的请求 RequestMapping(value"/Content",methodRequestMethod.POST,consumes"application/json") public String Consumes(RequestBody Map param){ return…

windows远程免密码登陆

1、按下WindowsR,打开运行窗口&#xff0c;输入gpedit.msc 2、依次选择计算机设置-- Windows 设置--安全设置--本地策略--安全选项 3、双击进入--帐户&#xff1a;使用空白密码的本地帐户只允许进行控制台登录 双击打开 参考 百度安全验证 Win11提示凭证不足无法访问这台打…

C++ std::vector及使用时的常见优化策略

std::vector 是 C 标准模板库&#xff08;STL&#xff09;中的一个动态数组容器。它提供了动态大小调整和高效的随机访问功能&#xff0c;非常适合需要频繁插入、删除和访问元素的场景。std::vector 是在 <vector> 头文件中定义的&#xff0c;并且位于 std 命名空间中。 …

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

案例名称-【福建省气象综合治理区块链平台】 ■ 实施单位 福建福链科技有限公司 ■ 业主单位 福建省气象信息中心 ■ 上线时间 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…