手写java性能测试框架的实现示例

目录
  • 引言
  • 代码分享
  • 基础类实现
  • 数据库的实现
  • concurrent类

引言

之前写过一个性能测试框架,只是针对单一的HTTP接口的测试,对于业务接口和非HTTP接口还无非适配,刚好前端时间工作中用到了,就更新了自己的测试框架,这次不再以请求为基础,而是以方法为基础,这样就可以避免了单一性,有一个base类,然后其他的各种单一性请求在单独写一个适配类就好了,如果只是临时用,直接重新实现base即可。

代码分享

package com.fun.frame.thead;
import com.fun.frame.SourceCode;
import com.fun.frame.excute.Concurrent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import static com.fun.utils.Time.getTimeStamp;
/**
 * 多线程任务基类,可单独使用
 */
public abstract class ThreadBase<T> extends SourceCode implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(ThreadBase.class);
    /**
     * 任务请求执行次数
     */
    public int times;
    /**
     * 计数锁
     * <p>
     * 会在concurrent类里面根据线程数自动设定
     * </p>
     */
    CountDownLatch countDownLatch;
    /**
     * 用于设置访问资源
     */
    public T t;
    public ThreadBase(T t) {
        this();
        this.t = t;
    }
    public ThreadBase() {
        super();
    }
    /**
     * groovy无法直接访问t,所以写了这个方法
     *
     * @return
     */
    public String getT() {
        return t.toString();
    }
    @Override
    public void run() {
        try {
            before();
            List<Long> t = new ArrayList<>();
            long ss = getTimeStamp();
            for (int i = 0; i < times; i++) {
                long s = getTimeStamp();
                doing();
                long e = getTimeStamp();
                t.add(e - s);
            }
            long ee = getTimeStamp();
            logger.info("执行次数:{},总耗时:{}", times, ee - ss);
            Concurrent.allTimes.addAll(t);
        } catch (Exception e) {
            logger.warn("执行任务失败!", e);
        } finally {
            after();
            if (countDownLatch != null)
                countDownLatch.countDown();
        }
    }
    /**
     * 运行待测方法的之前的准备
     */
    protected abstract void before();
    /**
     * 待测方法
     *
     * @throws Exception
     */
    protected abstract void doing() throws Exception;
    /**
     * 运行待测方法后的处理
     */
    protected abstract void after();
    public void setCountDownLatch(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
    public void setTimes(int times) {
        this.times = times;
    }
}

基础类实现

下面是几个实现过的基础类:

package com.fun.frame.thead;
import com.fun.httpclient.ClientManage;
import com.fun.httpclient.FanLibrary;
import com.fun.httpclient.GCThread;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
 * http请求多线程类
 */
public class RequestThread extends ThreadBase {
    static Logger logger = LoggerFactory.getLogger(RequestThread.class);
    /**
     * 请求
     */
    public HttpRequestBase request;
    /**
     * 单请求多线程多次任务构造方法
     *
     * @param request 被执行的请求
     * @param times   每个线程运行的次数
     */
    public RequestThread(HttpRequestBase request, int times) {
        this.request = request;
        this.times = times;
    }
    @Override
    public void before() {
        request.setConfig(FanLibrary.requestConfig);
        GCThread.starts();
    }
    @Override
    protected void doing() throws Exception {
        getResponse(request);
    }
    @Override
    protected void after() {
        GCThread.stop();
    }
    /**
     * 多次执行某个请求,但是不记录日志,记录方法用 loglong
     * <p>此方法只适应与单个请求的重复请求,对于有业务联系的请求暂时不能适配</p>
     *
     * @param request 请求
     * @throws IOException
     */
    void getResponse(HttpRequestBase request) throws IOException {
        CloseableHttpResponse response = ClientManage.httpsClient.execute(request);
        String content = FanLibrary.getContent(response);
        if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
            logger.warn("响应状态码:{},响应内容:{}", content, response.getStatusLine());
        if (response != null) response.close();
    }
}

数据库的实现

package com.fun.frame.thead;
import com.fun.interfaces.IMySqlBasic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
/**
 * 数据库多线程类
 */
public class QuerySqlThread extends ThreadBase {
    private static Logger logger = LoggerFactory.getLogger(QuerySqlThread.class);
    String sql;
    IMySqlBasic base;
    public QuerySqlThread(IMySqlBasic base, String sql, int times) {
        this.times = times;
        this.sql = sql;
        this.base = base;
    }
    @Override
    public void before() {
        base.getConnection();
    }
    @Override
    protected void doing() throws SQLException {
        base.excuteQuerySql(sql);
    }
    @Override
    protected void after() {
        base.mySqlOver();
    }
}

concurrent类

package com.fun.frame.excute;
import com.fun.bean.PerformanceResultBean;
import com.fun.frame.Save;
import com.fun.frame.SourceCode;
import com.fun.frame.thead.ThreadBase;
import com.fun.profile.Constant;
import com.fun.utils.Time;
import com.fun.utils.WriteRead;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Concurrent {
    private static Logger logger = LoggerFactory.getLogger(Concurrent.class);
    /**
     * 线程任务
     */
    public ThreadBase thread;
    public List<ThreadBase> threads;
    public int num;
    public static Vector<Long> allTimes = new Vector<>();
    ExecutorService executorService;
    CountDownLatch countDownLatch;
    /**
     * @param thread 线程任务
     * @param num    线程数
     */
    public Concurrent(ThreadBase thread, int num) {
        this(num);
        this.thread = thread;
    }
    /**
     * @param threads 线程组
     */
    public Concurrent(List<ThreadBase> threads) {
        this(threads.size());
        this.threads = threads;
    }
    public Concurrent(int num) {
        this.num = num;
        executorService = Executors.newFixedThreadPool(num);
        countDownLatch = new CountDownLatch(num);
    }
    /**
     * 执行多线程任务
     */
    public PerformanceResultBean start() {
        long start = Time.getTimeStamp();
        for (int i = 0; i < num; i++) {
            ThreadBase thread = getThread(i);
            thread.setCountDownLatch(countDownLatch);
            executorService.execute(thread);
        }
        shutdownService(executorService, countDownLatch);
        long end = Time.getTimeStamp();
        logger.info("总计" + num + "个线程,共用时:" + Time.getTimeDiffer(start, end) + "秒!");
        return over();
    }
    private static void shutdownService(ExecutorService executorService, CountDownLatch countDownLatch) {
        try {
            countDownLatch.await();
            executorService.shutdown();
        } catch (InterruptedException e) {
            logger.warn("线程池关闭失败!", e);
        }
    }
    private PerformanceResultBean over() {
        Save.saveLongList(allTimes, num);
        return countQPS(num);
    }
    ThreadBase getThread(int i) {
        if (threads == null) return thread;
        return threads.get(i);
    }
    /**
     * 计算结果
     * <p>此结果仅供参考</p>
     *
     * @param name 线程数
     */
    public static PerformanceResultBean countQPS(int name) {
        List<String> strings = WriteRead.readTxtFileByLine(Constant.LONG_Path + name + Constant.FILE_TYPE_LOG);
        int size = strings.size();
        int sum = 0;
        for (int i = 0; i < size; i++) {
            int time = SourceCode.changeStringToInt(strings.get(i));
            sum += time;
        }
        double v = 1000.0 * size * name / sum;
        PerformanceResultBean performanceResultBean = new PerformanceResultBean(name, size, sum / size, v);
        performanceResultBean.print();
        return performanceResultBean;
    }
}

redis实现类缺失,因为没有遇到需要单独实现的需求。

关于用代码还是用工具实现并发,我个人看法所有所长,单究其根本,必然是代码胜于工具,原因如下:门槛高,适应性强;贴近开发,利于调优。

性能测试,并发只是开始,只有一个好的开始才能进行性能数据分析,性能参数调优。所以不必拘泥于到底使用哪个工具那种语言,据我经验来说:基本的测试需求都是能满足的,只是实现的代价不同。

groovy是一种基于JVM的动态语言,我觉得最大的优势有两点

  • 第一:于java兼容性非常好,大部分时候吧groovy的文件后缀改成java直接可以用,反之亦然。java的绝大部分库,groovy都是可以直接拿来就用的。这还带来了另外一个有点,学习成本低,非常低,直接上手没问题,可以慢慢学习groovy不同于Java的语法;
  • 第二:编译器支持变得更好,现在用的intellij的ide,总体来说已经比较好的支持groovy语言了,写起代码来也是比较顺滑了,各种基于groovy的框架工具也比较溜,特别是Gradle构建工具,比Maven爽很多。

以上就是java性能测试框架手写实现示例的详细内容,更多关于java 性能测试框架的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解Java使用JMH进行基准性能测试

    目录 一.前言 二.JMH概述 1.什么是JMH 2.JMH适用的典型场景 3.JMH基本概念 三.JMH的使用 1.快速跑起来 2.JMH常用注解详细介绍 四.小结 附: 一.前言 在日常开发工作当中,开发人员可能有这些困惑:自己写的这个方法性能到底怎么样?在原接口实现方法中添加了新的业务逻辑,对整个接口的性能影响有多少?有多种实现方式(或开源类库),到底哪一种性能更好?- 当遇到类似困惑或者说问题的时候,怎么办呢?当然是测试验证,实践出真知!本文讲述的就是一个方法级别的性能测试工具--JMH

  • Java常用排序算法及性能测试集合

    现在再回过头理解,结合自己的体会, 选用最佳的方式描述这些算法,以方便理解它们的工作原理和程序设计技巧.本文适合做java面试准备的材料阅读. 先附上一个测试报告: Array length: 20000bubbleSort : 766 msbubbleSortAdvanced : 662 msbubbleSortAdvanced2 : 647 msselectSort : 252 msinsertSort : 218 msinsertSortAdvanced : 127 msinsertSor

  • Java中Map的遍历方法及性能测试

    1. 阐述 对于Java中Map的遍历方式,很多文章都推荐使用entrySet,认为其比keySet的效率高很多.理由是:entrySet方法一次拿到所有key和value的集合:而keySet拿到的只是key的集合,针对每个key,都要去Map中额外查找一次value,从而降低了总体效率.那么实际情况如何呢? 为了解遍历性能的真实差距,包括在遍历key+value.遍历key.遍历value等不同场景下的差异,我试着进行了一些对比测试. 2. 对比测试 一开始只进行了简单的测试,但结果却表明k

  • java8中parallelStream性能测试及结果分析

    测试1 @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 20, time = 3, timeUnit = TimeUnit.SECONDS) @Fork(1) @State(Scope.Benchmark) public cla

  • Java中的StringBuilder性能测试

    在看KMP算法时,想要简单的统计一下执行时间和性能. 得出的结论是: Java的String的indexOf方法性能最好,其次是KMP算法,其次是传统的BF算法,当然,对比有点牵强,SUN的算法也使用Java来实现.用的看着不像是KMP,还需要详细研究一下. 测试代码如下所示: package com.test.test.kmp; import java.util.Random; public class KMPTest { public static void main(String[] ar

  • 浅谈Java基准性能测试之JMH

    目录 一.JMH vs JMeter 二.JMH基本用法 2.1.创建JMH项目 2.2.编写基准测试代码 2.3.JMH打包.运行 2.4.JMH与Springboot 三.JMH注解 3.1.JMH Benchmark Modes 3.2.Benchmark Time Units 3.3.Benchmark State 3.4.State Object @Setup @TearDown 3.5.Fork 3.6.Thread 3.7.Warmup 3.8.Measurement 四.输出测试

  • 手写java性能测试框架的实现示例

    目录 引言 代码分享 基础类实现 数据库的实现 concurrent类 引言 之前写过一个性能测试框架,只是针对单一的HTTP接口的测试,对于业务接口和非HTTP接口还无非适配,刚好前端时间工作中用到了,就更新了自己的测试框架,这次不再以请求为基础,而是以方法为基础,这样就可以避免了单一性,有一个base类,然后其他的各种单一性请求在单独写一个适配类就好了,如果只是临时用,直接重新实现base即可. 代码分享 package com.fun.frame.thead; import com.fun

  • 手写java性能测试框架第二版

    目录 引言 第二版的threadbase代码如下 固定次数模式的压测虚拟类 固定时间模式虚拟类 HTTPrequestbase为基础的多线程类 固定次数模式的多线程类 固定时间模式的多线程类 使用Demo: 引言 依照领导要求区分了两种压测模式:固定次数压测和固定时间压测.此前一直沿用的都是固定次数,所以本次第二版剥离了固定次数的模式增加了固定时间的模式. 这是第一版:性能测试框架 第二版的threadbase代码如下 package com.fun.base.constaint; import

  • 手写Java LockSupport的示例代码

    目录 前言 LockSupport实现原理 自己动手实现自己的LockSupport 实现原理 自己实现LockSupport协议规定 工具 具体实现 完整代码 JVM实现一瞥 总结 前言 在JDK当中给我们提供的各种并发工具当中,比如ReentrantLock等等工具的内部实现,经常会使用到一个工具,这个工具就是LockSupport.LockSupport给我们提供了一个非常强大的功能,它是线程阻塞最基本的元语,他可以将一个线程阻塞也可以将一个线程唤醒,因此经常在并发的场景下进行使用. Lo

  • Java手写持久层框架的详细代码

    目录 前言 JDBC操作回顾及问题分析 1.定义配置xml文件 2.读取配置文件 3.定义sql操作接口SqlSession 4.编写数据库执行逻辑 5.调用测试 ⾃定义框架优化 总结 本文适合有一定java基础的同学,通过分析jdbc存在的问题,进行手写自定义持久层框架,可以更加清楚常用的mybatis等开源框架的原理. 前言 本文适合有一定java基础的同学,通过自定义持久层框架,可以更加清楚常用的mybatis等开源框架的原理. JDBC操作回顾及问题分析 学习java的同学一定避免不了接

  • 利用Java手写一个简易的lombok的示例代码

    目录 1.概述 2.lombok使用方法 3.lombok原理解析 4.手写简易lombok 1.概述 在面向对象编程中,必不可少的需要在代码中定义对象模型,而在基于Java的业务平台开发实践中尤其如此.相信大家在平时开发中也深有感触,本来是没有多少代码开发量的,但是因为定义的业务模型对象比较多,而需要重复写Getter/Setter.构造器方法.字符串输出的ToString方法.Equals/HashCode方法等.我们都知道Lombok能够替大家完成这些繁琐的操作,但是其背后的原理很少有人会

  • Java实现手写乞丐版线程池的示例代码

    目录 前言 线程池的具体实现 线程池实现思路 线程池实现代码 线程池测试代码 杂谈 总结 前言 在上篇文章线程池的前世今生当中我们介绍了实现线程池的原理,在这篇文章当中我们主要介绍实现一个非常简易版的线程池,深入的去理解其中的原理,麻雀虽小,五脏俱全. 线程池的具体实现 线程池实现思路 任务保存到哪里? 在上篇文章线程池的前世今生当中我们具体去介绍了线程池当中的原理.在线程池当中我们有很多个线程不断的从任务池(用户在使用线程池的时候不断的使用execute方法将任务添加到线程池当中)里面去拿任务

  • 手写Vue2.0 数据劫持的示例

    一:搭建webpack 简单的搭建一下webpack的配置.新建一个文件夹,然后init一下.之后新建一个webpack.config.js文件,这是webpack的配置文件.安装一下简单的依赖. npm install webpack webpack-cli webpack-dev-server -D 在同级目录下新建一个public/index.html和src/index.js,作为出口文件和入口文件. j简单配置一下webpack, 在webpack.config.js文件中: cons

  • Pytorch实现的手写数字mnist识别功能完整示例

    本文实例讲述了Pytorch实现的手写数字mnist识别功能.分享给大家供大家参考,具体如下: import torch import torchvision as tv import torchvision.transforms as transforms import torch.nn as nn import torch.optim as optim import argparse # 定义是否使用GPU device = torch.device("cuda" if torch

  • 学生视角手把手带你写Java 线程池

    目录 Java手写线程池(第一代) 手写线程池-定义参数 手写线程池-构造器 手写线程池-默认构造器 手写线程池-execute方法 手写线程池-处理任务 手写线程池-优雅关闭线程池 手写线程池-暴力关闭线程池 手写线程池-源代码 问题 Java手写线程池(第一代) 经常使用线程池,故今天突发奇想,手写一个线程池,会有很多不足,请多多宽容.因为这也是第一代的版本,后续会更完善. 手写线程池-定义参数 private final AtomicInteger taskcount=new Atomic

  • Java实现手写一个线程池的示例代码

    目录 概述 线程池框架设计 代码实现 阻塞队列的实现 线程池消费端实现 获取任务超时设计 拒绝策略设计 概述 线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和细节吗?如果直接去看jdk源码的话,可能有一定的难度,那么我们可以先通过手写一个简单的线程池框架,去掌握线程池的基本原理后,再去看jdk的线程池源码就会相对容易,而且不容易忘记. 线程池框架设计 我们都知道,线程资源的创建和销毁并不是没有代价的,甚至开销是非常高的.同

随机推荐