LongAddr

目录

1. 引言

2. AtomicInteger的局限性

3. AtomicInteger与LongAdder 的性能差异

4.LongAdder 的结构

LongAddr架构

Striped64中重要的属性

 Striped64中一些变量或者方法的定义

Cell类

5. 分散热点的原理

具体流程图

6. 在实际项目中的应用

7. 总结

1. 引言

在这一部分,可以简要介绍并发编程中的挑战,以及为什么传统的累加方式可能在高并发情况下表现不佳。引出LongAddr作为一种解决方案的背景。

LongAddr属于原子操作增强类,在传统的多线程编程中,我们可能会使用 synchronized 关键字或者 ReentrantLock 来保证对共享变量的原子性操作。然而,这些方法在高度并发的场景下可能会引起性能瓶颈。原子类中的AtomicInteger可以解决这个问题,但同时又出现了LongAddr来提供了一种更高效的并发累加方案。

2. AtomicInteger的局限性

  • 竞争热点

当多个线程同时竞争修改同一个 AtomicInteger实例时,会发生竞争热点。所有的线程都试图通过 CAS 操作来更新同一变量,这可能导致竞争激烈,降低性能。

3. AtomicInteger与LongAdder 的性能差异

需求:热点商品点赞计算器,点赞数加加统计,不要求实时精确;

代码:使用50个线程,每个线程100W次,总点赞数出来。

class ClickNumber
{int number = 0;public synchronized void add_Synchronized(){number++;}AtomicInteger atomicInteger = new AtomicInteger();public void add_AtomicInteger(){atomicInteger.incrementAndGet();}AtomicLong atomicLong = new AtomicLong();public void add_AtomicLong(){atomicLong.incrementAndGet();}LongAdder longAdder = new LongAdder();public void add_LongAdder(){longAdder.increment();//longAdder.sum();}LongAccumulator longAccumulator = new LongAccumulator((x,y) -> x+y,0);public void add_LongAccumulator(){longAccumulator.accumulate(1);}}/****  50个线程,每个线程100W次,总点赞数出来*/
public class LongAdderCalcDemo
{public static final int SIZE_THREAD = 50;public static final int _1W = 10000;public static void main(String[] args) throws InterruptedException{ClickNumber clickNumber = new ClickNumber();long startTime;long endTime;CountDownLatch countDownLatch1 = new CountDownLatch(SIZE_THREAD);CountDownLatch countDownLatch2 = new CountDownLatch(SIZE_THREAD);CountDownLatch countDownLatch3 = new CountDownLatch(SIZE_THREAD);CountDownLatch countDownLatch4 = new CountDownLatch(SIZE_THREAD);CountDownLatch countDownLatch5 = new CountDownLatch(SIZE_THREAD);//========================startTime = System.currentTimeMillis();for (int i = 1; i <=SIZE_THREAD; i++) {new Thread(() -> {try{for (int j = 1; j <=100 * _1W; j++) {clickNumber.add_Synchronized();}}catch (Exception e){e.printStackTrace();}finally {countDownLatch1.countDown();}},String.valueOf(i)).start();}countDownLatch1.await();endTime = System.currentTimeMillis();System.out.println("----costTime: "+(endTime - startTime) +" 毫秒"+"\t add_Synchronized"+"\t"+clickNumber.number);startTime = System.currentTimeMillis();for (int i = 1; i <=SIZE_THREAD; i++) {new Thread(() -> {try{for (int j = 1; j <=100 * _1W; j++) {clickNumber.add_AtomicInteger();}}catch (Exception e){e.printStackTrace();}finally {countDownLatch2.countDown();}},String.valueOf(i)).start();}countDownLatch2.await();endTime = System.currentTimeMillis();System.out.println("----costTime: "+(endTime - startTime) +" 毫秒"+"\t add_AtomicInteger"+"\t"+clickNumber.atomicInteger.get());startTime = System.currentTimeMillis();for (int i = 1; i <=SIZE_THREAD; i++) {new Thread(() -> {try{for (int j = 1; j <=100 * _1W; j++) {clickNumber.add_AtomicLong();}}catch (Exception e){e.printStackTrace();}finally {countDownLatch3.countDown();}},String.valueOf(i)).start();}countDownLatch3.await();endTime = System.currentTimeMillis();System.out.println("----costTime: "+(endTime - startTime) +" 毫秒"+"\t add_AtomicLong"+"\t"+clickNumber.atomicLong.get());startTime = System.currentTimeMillis();for (int i = 1; i <=SIZE_THREAD; i++) {new Thread(() -> {try{for (int j = 1; j <=100 * _1W; j++) {clickNumber.add_LongAdder();}}catch (Exception e){e.printStackTrace();}finally {countDownLatch4.countDown();}},String.valueOf(i)).start();}countDownLatch4.await();endTime = System.currentTimeMillis();System.out.println("----costTime: "+(endTime - startTime) +" 毫秒"+"\t add_LongAdder"+"\t"+clickNumber.longAdder.longValue());startTime = System.currentTimeMillis();for (int i = 1; i <=SIZE_THREAD; i++) {new Thread(() -> {try{for (int j = 1; j <=100 * _1W; j++) {clickNumber.add_LongAccumulator();}}catch (Exception e){e.printStackTrace();}finally {countDownLatch5.countDown();}},String.valueOf(i)).start();}countDownLatch5.await();endTime = System.currentTimeMillis();System.out.println("----costTime: "+(endTime - startTime) +" 毫秒"+"\t add_LongAccumulator"+"\t"+clickNumber.longAccumulator.longValue());}
}
----costTime: 895 毫秒	 add_Synchronized	50000000
----costTime: 450 毫秒	 add_AtomicInteger	50000000
----costTime: 445 毫秒	 add_AtomicLong	50000000
----costTime: 41 毫秒	 add_LongAdder	50000000
----costTime: 41 毫秒	 add_LongAccumulator	50000000

        通过结果能看出在duoLongAddr的性能要比synchronized锁和AtomicInteger要好。

4.LongAdder 的结构

LongAddr架构

       

        从上图可以看出LongAdder是Striped64的子类。

Striped64中重要的属性

/** Number of CPUS, to place bound on table size        CPU数量,即cells数组的最大长度 */
static final int NCPU = Runtime.getRuntime().availableProcessors();/*** Table of cells. When non-null, size is a power of 2.
cells数组,为2的幂,2,4,8,16.....,方便以后位运算*/
transient volatile Cell[] cells;/**基础value值,当并发较低时,只累加该值主要用于没有竞争的情况,通过CAS更新。* Base value, used mainly when there is no contention, but also as* a fallback during table initialization races. Updated via CAS.*/
transient volatile long base;/**创建或者扩容Cells数组时使用的自旋锁变量调整单元格大小(扩容),创建单元格时使用的锁。* Spinlock (locked via CAS) used when resizing and/or creating Cells. */
transient volatile int cellsBusy;

 Striped64中一些变量或者方法的定义

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

Cell类

Cell类是 java.util.concurrent.atomic 下 Striped64 的一个内部类

5. 分散热点的原理

        LongAdder的基本思路就是分散热点,将value值分散到一个Cell数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。如果要获取真正的long值,只要将各个槽中的变量值累加返回。
 
sum()会将所有Cell数组中的value和base累加作为返回值,核心的思想就是将之前AtomicLong一个value的更新压力分散到多个value中去,从而降级更新热点。

 

Value = Base +

总结:内部有一个base变量,一个Cell[]数组。

base变量:非竞态条件下,直接累加到该变量上,Cell[]数组:竞态条件下,累加个各个线程自己的槽Cell[i]中。

具体流程图

6. 在实际项目中的应用

  • 热点商品点赞计算器,点赞数加加统计,不要求实时精确。
  • 一个很大的List,里面都是int类型,实现加加。

7. 总结

当需要在高并发下有较好的性能表现,且对值的精确度要求不高时,可以使用。

即当需要保证性能,不要求精度,可以使用。

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

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

相关文章

抖音外卖商品模型

目录 一、抖音外卖商品模型 二、商家运营流程 &#xff08;一&#xff09;商家入驻流程 &#xff08;二&#xff09;商品发布流程 三、推广带货流程 &#xff08;一&#xff09;短视频带货 &#xff08;二&#xff09;直播视频带货 【直播工具】 【直播流程】 直播前…

Redis--13--缓存一致性问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 缓存一致性问题1、先更新缓存&#xff0c;再更新DB方案二&#xff1a;先更新DB&#xff0c;再更新缓存方案三&#xff1a;先删缓存&#xff0c;再写数据库推荐1&…

Ubuntu中安装IDEA,并配置桌面快捷方式

1、首先自己下载linux版本的idea 这一步省略不说了 2、在/usr/local/路径下新建安装目录IDEA&#xff1a; mkdir -p /usr/local/IDEA3、执行如下命令&#xff0c;解压下载的压缩包到指定目录&#xff1a; tar -zxvf ideaIU-2022.3.3.tar.gz -C /usr/local/IDEA 注意&#x…

[Golang] 高频次和高并发下的随机数重复问题的解决方案

一、概要&#xff1a; 在Golang中&#xff0c;获取随机数的方法一般会介绍有两种&#xff0c;一种是基于math/rand的伪随机&#xff0c;一种是基于crypto/rand的真随机。其中&#xff0c;math/rand由于其伪随机的原理&#xff0c;经常会出现重复的随机数&#xff0c;导致在需要…

(四)基于高尔夫优化算法GOA求解无人机三维路径规划研究(MATLAB代码)

一、无人机模型简介&#xff1a; 单个无人机三维路径规划问题及其建模_IT猿手的博客-CSDN博客 参考文献&#xff1a; [1]胡观凯,钟建华,李永正,黎万洪.基于IPSO-GA算法的无人机三维路径规划[J].现代电子技术,2023,46(07):115-120 二、高尔夫优化算法GOA简介 高尔夫优化算法…

461. 汉明距离

461. 汉明距离 不难 class Solution {public int hammingDistance(int x, int y) {int res 0;while(x!0 || y!0) {if((x&1) ! (y&1))res ;x>>1;y>>1;}return res;} }

【LeeCode】160.链表相交

给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结果后&#…

rman 工作常用

RMAN> backup archivelog all delete input; backup as compressed backupset backupset all;###备份片的再压缩 all, or until time sysdate -7 RMAN> run { backup archivelog all; delete archivelog until time sysdate -1 like /u01/archives/TEST/%; delete…

MediaPipe 3D姿态估计简明教程

姿势检测是更多地了解视频和图像中人体的重要一步。 我们现有的模型支持 2D 姿态估计已经有一段时间了&#xff0c;你们中的许多人可能已经尝试过。 今天&#xff0c;我们在 TF.js 姿势检测 API 中推出第一个 3D 模型。 3D 姿态估计为健身、医疗、动作捕捉等应用开辟了新的设计…

简易FIR数字滤波器

摘 要 随着科学技术的飞速发展&#xff0c;数字信号处理技术广泛的应用在各种领域中&#xff0c;而数字滤波技术在数字信号处理中占有极其重要的地位。传统的模拟滤波器已经很难满足工业生产的需求&#xff0c;所以&#xff0c;对数字滤波器的研究具有很重要的实际意义。相对于…

分享一个用C#写的Aspose.Pdf生成pdf的工具类

公共类 公共属性 标题级别 对应的标题样式 汉字与数字标题对应关系 using Aspose.Words; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using System.Text.RegularExpressions;namespace Common.Bo {public class CommonStyl…

WordPress外贸站优化工具,WordPress外贸SEO优化方法

WordPress外贸站是跨国企业拓展市场、提升品牌知名度的理想选择。然而&#xff0c;如何通过SEO优化、原创文章生成以及留心站点优化的事项&#xff0c;成为众多站长关注的焦点。 SEO&#xff0c;即搜索引擎优化&#xff0c;是提高网站在搜索引擎结果中排名的关键。首先&#x…

云计算:数字时代的引擎

引言 云计算&#xff0c;作为现代信息技术领域的一项革命性创新&#xff0c;已经深刻改变了我们处理数据和应用的方式。它已经从仅仅是一个概念演变为一个全球范围内广泛应用的技术。云计算为个人、企业和政府机构提供了强大的计算能力、灵活性和可扩展性&#xff0c;同时降低…

JavaScript递归

前端面试大全JavaScript递归 &#x1f31f;经典真题 &#x1f31f;递归 &#x1f31f;真题解答 &#x1f31f;总结 &#x1f31f;经典真题 使用递归完成 1 到 100 的累加 &#x1f31f;递归 A recursive method is a method that calls itself. 递归调用是一种特殊的调…

数据集的标签文件【无标题】

这里写目录标题 读取数据集 .json是用来存储简单的数据结构和对象的文件。json是一种轻量级的数据交换格式 给了 数据集的标签文件&#xff0c; 读取数据集 .json的本质是字典 读取Json文件&#xff1a;json.load() import json with open(train.json,r,encodingutf-8) as f…

[最优化理论] 梯度下降法 + 精确线搜索(单峰区间搜索 + 黄金分割)C++ 代码

这是我的课程作业&#xff0c;用了 Eigen 库&#xff0c;最后的输出是 latex 的表格的一部分 具体内容就是 梯度下降法 精确线搜索&#xff08;单峰区间搜索 黄金分割&#xff09; 从书本的 Matlab 代码转译过来的其实&#xff0c;所以应该是一看就懂了 这里定义了两个测试…

使用pytorch从零开始实现迷你GPT

生成式建模知识回顾: [1] 生成式建模概述 [2] Transformer I&#xff0c;Transformer II [3] 变分自编码器 [4] 生成对抗网络&#xff0c;高级生成对抗网络 I&#xff0c;高级生成对抗网络 II [5] 自回归模型 [6] 归一化流模型 [7] 基于能量的模型 [8] 扩散模型 I, 扩散模型 II…

wordpress建站优化加速教程-Redis加速

这篇文章适合宝塔面板&#xff0c;在宝塔面板安装 Redis 实现网站加速&#xff08; Redis是一个高性能的key-value数据库(PHP连接redis&#xff0c;需PHP设置中安装redis扩展) &#xff09;。对在word press网站有着明显的加速效果。关于Redis具体说明请自己百度&#xff0c;…

编程中常见的技术难题有哪些?By AI

编程对于现代社会发展的重要性 编程&#xff0c;即按照特定的规则和逻辑&#xff0c;为计算机设计指令的过程&#xff0c;已经深深地融入现代社会的各个角落。它对人们的生活、工作和科技发展产生了深远的影响。 首先&#xff0c;编程改变了人们的生活方式。如今&#xff0c;…

Qt 如何操作SQLite3数据库?数据库创建和表格的增删改查?

# 前言 项目源码下载 https://gitcode.com/m0_45463480/QSQLite3/tree/main # 第一步 项目配置 平台:windows10 Qt版本:Qt 5.14.2 在.pro添加 QT += sql 需要的头文件 #include <QSqlDatabase>#include <QSqlError>#include <QSqlQuery>#include &…