高性能并发计数器的比较

参考文档:https://baijiahao.baidu.com/s?id=1742540809477784106&wfr=spider&for=pc

一、常用的并发计数方法

1、synchronized

synchronized早期是一个重量级锁,因为线程竞争锁会引起操作系统用户态和内核态切换,浪费资源,效率不高。jdk1.6对 synchronized 做了性能优化,它会经历偏向锁,轻量级锁,最后才到重量级锁,性能提升显著。jdk1.7的 ConcurrentHashMap 是基于ReentrantLock的实现了锁,但在jdk1.8之后又替换成了 synchronized,籍此可见JVM团队对synchronized的信心;

2、原子更新整型 AtomicInteger、AtomicLong

JDK1.5提供了并发的Integer/Long的操作工具类 AtomicInteger、AtomicLong。AtomicLong底层是一个乐观锁,不用阻塞线程,其利用底层操作系统的CAS来保证原子性,即在一个死循环内不断执行CAS操作,直到成功。其缺陷是当并发较大时,大量线程不断CAS,存在多次的CAS操作失败,使CPU升高,效率降低。

AtomicLong value = new AtomicLong(0);
value.incrementAndGet();

3、LongAdder [单机]

在JDK8中新增了LongAdder,这是针对Long类型的数据的操作工具类。在ConcurrentHashMap中,对Map分割成多个segment,这样多个Segment的操作就可以并行执行,从而提高性能。在JDK8中,LongAdder与ConcurrentHashMap类似,将内部操作数据value分离成一个Cell数组,每个线程访问时,通过Hash等算法映射到其中一个Cell上。 计算最终的数据结果,则是各个Cell数组的累计求和。

4、Redisson分布式累加器 [分布式]

基于Redis的Redisson分布式长整型累加器(LongAdder)采用了与java.util.concurrent.atomic.LongAdder 类似的接口。通过利用客户端内置的 LongAdder 对象,为分布式环境下递增和递减操作提供了很高的性能。其性能最高比分布式 AtomicLong 对象快 10^4 倍。

RLongAddr itheimaLongAddr = redission.getLongAddr(“itheimaLongAddr”);
itheimaLongAddr.add(100);
itheimaLongAddr.increment();
itheimaLongAddr.increment();
itheimaLongAddr.sum();

基于Redis的Redisson分布式双精度浮点累加器(DoubleAdder)采用了与 java.util.concurrent.atomic.DoubleAdder 类似的接口。通过利用客户端内置的 DoubleAdder 对象,为分布式环境下递增和递减操作提供了很高的性能。其性能最高比分布式 AtomicDouble 对象快 10^4 倍。

RLongDouble itheimaDouble = redission.getLongDouble(“itheimaLongDouble”);
itheimaDouble.add(100);
itheimaDouble.increment();
itheimaDouble.increment();
itheimaDouble.sum();

二、并发计数方法性能测试

1、测试程序

    private long count = 0;@Testpublic void counterCompare() {this.counterCousum(1,   1000 * 1000);this.counterCousum(20,  1000 * 1000);this.counterCousum(40,  1000 * 1000);this.counterCousum(60,  1000 * 1000);this.counterCousum(100, 1000 * 1000);}/*** @param threadCount 线程数量* @param increTimes 每个线程自增次数*/private void counterCousum(int threadCount, int increTimes) {long start;try {System.out.println(String.format("线程数量: %s, 自增次数: %s", threadCount, increTimes));start = System.currentTimeMillis();this.synchronizedTest(threadCount, increTimes);System.out.println("Synchronized 耗时: " + (System.currentTimeMillis() - start));start = System.currentTimeMillis();this.atomicLongTest(threadCount, increTimes);System.out.println("AtomicLong 耗时: " + (System.currentTimeMillis() - start));start = System.currentTimeMillis();this.longAdderTest(threadCount, increTimes);System.out.println("LongAdder 耗时: " + (System.currentTimeMillis() - start) + "\n");} catch (Exception e) {e.printStackTrace();}}private void atomicLongTest(int threadCount, int times) throws InterruptedException {AtomicLong count = new AtomicLong();List<Thread> threadList = new ArrayList<>();for (int i = 0; i < threadCount; i++) {threadList.add(new Thread(()-> {for (int j = 0; j < times; j++) {count.incrementAndGet();}}));}for (Thread thread : threadList) {thread.start();}for (Thread thread : threadList) {thread.join();}}private void synchronizedTest(int threadCount, int times) throws InterruptedException {List<Thread> threadList = new ArrayList<>();for (int i = 0; i < threadCount; i++) {threadList.add(new Thread(()-> {for (int j = 0; j < times; j++) {add();}}));}for (Thread thread : threadList) {thread.start();}for (Thread thread : threadList) {thread.join();}}private synchronized void add() {count++;}private void longAdderTest(int threadCount, int times) throws InterruptedException {LongAdder count = new LongAdder();List<Thread> threadList = new ArrayList<>();for (int i = 0; i < threadCount; i++) {threadList.add(new Thread(()-> {for (int j = 0; j < times; j++) {count.increment();}}));}for (Thread thread : threadList) {thread.start();}for (Thread thread : threadList) {thread.join();}}

2、测试结果

在这里插入图片描述
synchronized、AtomicLong的耗时随着并发量的增大而增大,LongAdder的耗时保持相对稳定,性能优越 !!!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Element Plus中button按钮相关大全

一、基本用法 使用 type、plain、round 和 circle 来定义按钮的样式。 样式代码如下&#xff1a; <template><div class"mb-4"><el-button>Default</el-button><el-button type"primary">Primary</el-button><el…

C语言常见字符串函数模拟实现一

strlen模拟实现 重点&#xff1a;1.字符串已经\0作为结束标志&#xff0c;strlen返回的是字符串\0前面出现的字符个数&#xff08;不包含\0&#xff09; 2.参数指向的字符串必须要以\0结束。 3.注意函数的返回值是size_t&#xff0c;是无符号的&#xff0c;加减是无法对比的。…

卡西欧相机SD卡格式化后数据恢复指南

在数字摄影时代&#xff0c;卡西欧相机以其卓越的性能和便携性成为了众多摄影爱好者的首选。然而&#xff0c;随着拍摄量的增加&#xff0c;SD卡中的数据管理变得尤为重要。不幸的是&#xff0c;有时我们可能会因为操作失误或系统故障而将SD卡格式化&#xff0c;导致珍贵的照片…

数据类型转换中存在的问题分析

隐式类型转换&#xff08;implicit type conversion&#xff09; 隐式类型转换&#xff08;implicit type conversion&#xff09;包括整型提升&#xff08;integer promotion&#xff09;和标准算数转换&#xff08;usual arithmetic conversions&#xff09; 遵循较大范围优…

堡垒机(Bastion Host)概述

Bastion Host 堡垒机 一、什么是堡垒机&#xff1f; A bastion host is a computer specially designed to mitigate cyberattacks and manage access rights to an internal network. 堡垒机Bastion Host是一种专门设计用于缓解网络攻击并管理内部网络访问权限的计算机。 在…

肖扬新书《微权力下的项目管理》读书笔记2

一个核心思想&#xff1a;“借力” 合格的项目经理是不热衷于培养人的。项目经理的工作场景和职能经理的工作场景往往有很 大不同。职能经理的工作方式通常适用于常态化工作&#xff0c;要有足够的时间去培养人&#xff0c;先把人培 养起来&#xff0c;然后再干事&#xff0c;可…

加油卡APP定制搭建,让加油更便捷!

在汽车时代中&#xff0c;汽车的数量不断增加&#xff0c;加油已经成为了大众生活中不可缺少的一部分。同时&#xff0c;加油卡的出现也为大众的汽车加油提供了更多的优惠方式&#xff0c;为大众节省经济开支&#xff0c;为车主带来便利&#xff1b;同时加油卡的发展也提高了加…

2024年华为杯研赛(E题)数学建模竞赛解题思路|完整代码论文集合

我是Tina表姐&#xff0c;毕业于中国人民大学&#xff0c;对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在&#xff0c;我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…

如何远程访问局域网内的电脑?局域网内远程桌面怎么实现?揭秘4种干货技巧

想象一下&#xff0c;你正在办公室A&#xff0c;而你想访问办公室B里的某台电脑&#xff0c;却不想起身到另一楼层甚至是另一个房间。 如何不动身就能控制局域网内的另一台电脑呢&#xff1f; 这并不是科幻&#xff0c;而是完全可以通过远程桌面技术来实现。 今天&#xff0…

学习Java(一)类和对象

package demo.ceshi;public class Puppy {private int age;private String name;//构造器public Puppy( String name){this.name name;System.out.println("公主的名字叫&#xff1a;"name);}//设置age的值public void setAge(int age){this.age age;System.out.pr…

智慧仓储-AI销量预测

1、预测系统技术选型 基础层&#xff1a; Hbase、ClickHouse、Hdfs 用来做数据存储 框架层&#xff1a; 以 Spark RDD、Spark SQL、Hive 为主&#xff0c; MapReduce 程序占一小部分&#xff0c;是原先遗留下来的&#xff0c;目前正逐步替换成 Spark RDD。 选择 Spark 除了对…

rsyslogd 内存占用很高解决方案

在Kubernetes&#xff08;K8S&#xff09;集群中&#xff0c;监控日志是非常重要的&#xff0c;而rsyslogd是Linux系统中用于处理系统和应用程序日志的守护进程。有时候rsyslogd可能会占用较高的内存&#xff0c;这时候我们就需要对其进行优化和调整。 阿里云虚拟服务器&…

创客中国AIGC专题赛冠军天鹜科技:AI蛋白质设计引领者

“落霞与孤鹜齐飞,秋水共长天一色——这句出自《滕王阁序》的诗句,是我作为江西人熟记于心的佳句。它描绘的天地壮丽景色常浮现于我的脑海,正是这种豁达与壮观,启发我们将公司命名为‘天鹜科技’,我们希望将源自自然的蛋白质与现代科技的创新精神相结合,打造蛋白质设计与应用的…

16_Python的迭代器

在Python中&#xff0c;迭代是一个非常重要的概念。迭代通常指的是按照某种顺序逐个访问容器中的元素的行为。如使用for循环遍历取值的过程。 可迭代对象&#xff08;Iterable&#xff09; 可迭代对象是任何可以返回一个迭代器的对象。简单来说&#xff0c;它是可以逐一返回其…

机器学习模型中特征贡献度分析:预测贡献与错误贡献

在机器学习领域&#xff0c;特征重要性分析是一种广泛应用的模型解释工具。但是特征重要性并不等同于特征质量。本文将探讨特征重要性与特征有效性之间的关系&#xff0c;并引入两个关键概念&#xff1a;预测贡献度和错误贡献度。 核心概念 预测贡献度&#xff1a;衡量特征在…

【C++】—— stack queue deque

【C】—— stack & queue & deque 1 stack 与 queue 的函数接口2 适配器2.1 发现问题2.2 什么是适配器 3 stack 与 queue的模拟实现3.1 栈的基础框架3.2 栈的模拟实现3.3 队列的模拟实现 4 模板的按需实例化5 deque 的简单介绍5.1 vector 与list对比5.1.1 vector5.1.2 …

C++函数重载完成日期类相关计算

本文内容如下&#xff1a; 1.创建类以及函数的声明2.日期加减天数1.月份天数2.函数实现 3.日期比较大小4.日期减日期1.日期的前置和后置加加2.日期减日期的实现 5.内置类型的cout和cin本文代码如下&#xff1a; 要完成日期类的相关计算要创建自定义的类型&#xff0c;然后用函数…

获取IPV6地址的参考网站|nginx解析IPV6|linux服务器获取IPV6的方法

获取IPV6地址的参考网站 网址1 https://v6.ident.me/ 网址2 https://ifconfig.co/ 网址3 https://ifconfig.me/ IPV6检测站点推荐 网址1 http://ipv6-test.ch/ linux服务器获取IPV6的方法 以centos7为例 curl -6 ifconfig.mecurl -6 https://v6.ident.mecurl -6 https:…

python安装-升级

这里写自定义目录标题 欢迎使用Markdown编辑器 欢迎使用Markdown编辑器 运行python 或pycharm时报错 [notice] A new release of pip is available: 23.1.2 -> 24.2 [notice] To update, run: python.exe -m pip install --upgrade pipCMD 进入 DOS C:\Users\wang>pyt…

解密MQ消息积压:让你系统瞬间卡死的幕后黑手

文章目录 什么是MQ消息积压&#xff1f;消息积压的常见原因案例分析&#xff1a;如何处理消息积压&#xff1f;场景1&#xff1a;消费者处理速度过慢场景2&#xff1a;消息生产速度过快 如何预防消息积压&#xff1f;1. **监控与告警**2. **动态扩容**3. **限流与降级**4. **合…