ConcurrentHashMap性能测试

今天我特意来测试一下java.util.concurrent.ConcurrentHashMap的查询性能,其他增改的功能暂时不做测试了。关于另外一个可能的原因java.util.concurrent.atomic.AtomicLong,我们下期再测。有兴趣的可以先看看我之前对于更强大的多线程计数器java.util.concurrent.atomic.LongAdder的性能测试:性能测试中的LongAdder。下面是之前遇到两种不同类型的对象池的性能测试文章:通用池化框架GenericObjectPool性能测试、通用池化框架GenericKeyedObjectPool性能测试。

测试方案

先说一下思路和场景设计。思路还是沿用之前的性能测试,通过固定线程的性能模型进行测试,通过调整次数和线程数来测试java.util.concurrent.ConcurrentHashMap的性能表现。场景设计上我先把java.util.concurrent.ConcurrentHashMap添加N个key和value,然后通过多线程随机从这些key里面取值。

这样本地测试就有了三个变量线程数、次数、key的数量,本次重点放在了200线程以上的性能表现。

PS:硬件和软件配置参考以前的文章,这里就不多说了。

测试用例

照例方案依旧使用FunTester性能测试框架提供的能力,采取Groovy脚本实现。相信有一定Java基础的同学阅读起来是没有问题的。

package com.funtest.groovytest

import com.funtester.base.constaint.FixedThread
import com.funtester.base.constaint.ThreadBase
import com.funtester.frame.SourceCode
import com.funtester.frame.execute.Concurrent

import java.util.concurrent.ConcurrentHashMap

class ConcurrentHashMapTest extends SourceCode {

    static ConcurrentHashMap<Integer, Integer> maps = new ConcurrentHashMap<>()

    static int times = 1_0000

    static int threads = 200

    static int num = 100

    static def desc = "ConcurrentHashMap性能测试"

    public static void main(String[] args) {
        1.upto(num) {
            maps.put(it, it)
        }

        ThreadBase.COUNT = false
        RUNUP_TIME = 0
        new Concurrent(new FunTester(), threads, desc).start()
    }

    private static class FunTester extends FixedThread {


        FunTester() {
            super(null, times, true)
        }

        @Override
        protected void doing() throws Exception {
            maps.get(getRandomInt(num))
        }

        @Override
        FunTester clone() {
            return new FunTester()
        }
    }

}

测试结果

由于测试中基本都触碰到硬件(CPU)瓶颈,所以本次也就不记录CPU使用率了,相当于都是在CPU资源有限情况下的性能测试数据,其实测试中发现次数影响也不大。
在这里插入图片描述

测试到此,结论比较明显了,影响java.util.concurrent.ConcurrentHashMap的主要因素还是机器CPU资源不够用了。对于相同的资源情况下,线程数更低自然获得更强的单线程性能,如果增加线程确实可以获取更大的总体QPS。在key值方面,值越多,QPS越低。在测试次数上,自然是字数越多,QPS也大,也符合之前多次测试中的结论。

但是当我重新检查代码的时候却发现一个问题,在com.funtest.groovytest.ConcurrentHashMapTest.FunTester#doing方法中其实还有一段耗时的请求,就是com.funtester.frame.SourceCode#getRandomInt,经过我重新测试,发现java.util.concurrent.ConcurrentHashMap的性能得到了十几倍的提升。

不得不说我大意了,本期文章标题应当修改为java.util.concurrent.ThreadLocalRandom性能测试。

一下是com.funtester.frame.SourceCode#getRandomInt的内容:

/**
 * 获取随机数,获取1~num 的数字,包含 num
 *
 * @param num 随机数上限
 * @return 随机数
 */
public static int getRandomInt(int num) {
    return ThreadLocalRandom.current().nextInt(num) + 1;
}

我依此法重新测试了java.util.concurrent.atomic.AtomicLong,发现也是QPS超高,排除了我之前的想法。看来commons-pool2的瓶颈不在这两个地方。以后等我仔细再研究研究,有结论再跟大家分享。

最后: 可以在公众号:伤心的辣条 ! 自行领取一份216页软件测试工程师面试宝典文档资料【免费的】。以及相对应的视频学习教程免费分享!,其中包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。

学习不要孤军奋战,最好是能抱团取暖,相互成就一起成长,群众效应的效果是非常强大的,大家一起学习,一起打卡,会更有学习动力,也更能坚持下去。你可以加入我们的测试技术交流扣扣群:914172719(里面有各种软件测试资源和技术讨论)

喜欢软件测试的小伙伴们,如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值