Bootstrap

使用java简单模拟Jmeter的压测操作

使用java简单模拟Jmeter的压测操作

简介:本文演示怎么用java模拟Jmeter的压测操作

导包

首先需要导入hutool

Hutool 是一个 Java 工具包,它提供了一些常用的工具方法,旨在简化 Java 编程。Hutool 包含了多种工具类,例如:

日期时间处理:提供日期时间的解析、格式化、计算等。
字符串处理:字符串的拼接、分割、转换等。
文件操作:文件的读写、文件路径解析等。
加密解密:支持多种加密算法。
HTTP客户端:发送 HTTP 请求的工具。
JSON处理:JSON数据的解析和生成。
图像处理:生成验证码图片等。
Bean操作:Java Bean的属性操作等。
Hutool 的设计哲学是减少代码量,提高开发效率,让开发者能够更专注于业务逻辑的实现

<dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.11</version> <!-- 使用最新版本 -->
  </dependency>

编写压测代码

普通版

代码思路:

  1. URL定义:在代码中,你使用了一个字符串变量url来存储待压测的接口地址。在实际使用中,你需要将"xxxxxxxxxxxxxxx"替换为实际的URL。

  2. 线程数量:定义了一个整型变量threadCount,用来设置你想要模拟的并发请求数量。在你的代码中,这个值为20,意味着你将创建20个线程。

  3. 线程创建与启动:使用了一个for循环来创建新的线程。每次循环迭代都创建了一个新的Thread对象,并传入一个匿名内部类Runnable作为其目标。

  4. Runnable实现:匿名内部类实现了Runnable接口,并覆盖了run方法。这是线程执行的主体部分。

  5. 无限循环:在run方法内部,你使用了一个while(true)循环,这意味着线程一旦启动,将无限期地执行其中的代码。

  6. HTTP请求:在无限循环内部,使用Hutool工具类HttpUtil.get方法向指定的URL发送HTTP GET请求,并获取响应。由于使用了无限循环,这个请求将不断地被发送。

  7. 线程启动:调用start方法来启动新创建的线程,使其开始执行Runnable中的run方法。

  8. 并发执行:由于每个线程都是独立的,所以这20个线程将会并发地执行,模拟了20个用户同时对目标URL发起请求的场景。

public class JmeterTest {
    public static void main(String[] args) {
        String url = "xxxxxxxxxxxxxxx"; // 待压测的接口
        // 模拟底层请求
        int threadCount = 20;
        for (int i = 0; i < threadCount; ++ i)
        {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        String response = HttpUtil.get(url);
                    }
                }
            }).start();
        }
    }
}

使用线程池优化代码

线程池优化的好处

  1. 资源管理:线程池可以有效地管理线程资源,避免因频繁创建和销毁线程而导致的性能损耗。

  2. 并发控制:线程池通过限制最大线程数,可以控制同时运行的线程数量,避免因过多线程竞争系统资源而导致的性能问题。

  3. 提高响应速度:线程池中的线程是可复用的,当有新任务提交时,线程池可以快速地提供线程资源,而不需要等待新线程的创建。

  4. 异常处理:线程池可以集中处理线程中的异常,避免因异常导致线程意外终止。

  5. 灵活性:线程池提供了更多的灵活性,比如可以设置线程池的线程工厂、拒绝策略等。

  6. 生命周期管理:线程池有完整的生命周期,可以在任务执行完毕后优雅地关闭,释放所有资源。

  7. 任务调度:线程池可以更灵活地调度任务,支持定时任务和周期性任务。

  8. 监控和统计:线程池提供了方法来监控线程的运行状态,如活跃线程数、任务队列长度、已完成的任务数等。

  9. 减少系统负载:通过控制最大线程数,可以减少系统负载,避免因线程过多导致的资源竞争和上下文切换开销。

  10. 提高稳定性:线程池可以避免因线程数量过多而导致的系统不稳定。

  11. 更好的错误处理:使用线程池可以集中处理线程中的异常,而不是让每个线程单独处理,这有助于提高程序的健壮性。

  12. 线程复用:线程池中的线程执行完一个任务后,可以被重新用于执行其他任务,这减少了线程创建和销毁的开销。

  13. 可维护性:线程池提供了更好的可维护性,因为线程管理逻辑被封装在线程池的实现中,而不是分散在各个线程中。

  14. 可扩展性:线程池可以根据需要调整线程数量,以适应不同的负载需求,而不需要修改使用线程池的代码。

  15. 优雅的关闭:线程池提供了优雅关闭的机制,可以在程序结束时释放资源,而不是强制终止线程。

import cn.hutool.http.HttpUtil;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class JmeterTest {
    public static void main(String[] args) {
        String url = "xxxxxxxxxxxxxxx"; // 待压测的接口
        int threadCount = 20; // 线程数
        // 模拟底层请求
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        for (int i = 0; i < threadCount; ++ i){
            try {
                executorService.submit(()->{
                    while(true){
                        String response = HttpUtil.get(url);
                        System.out.println("Response:" + response);
                    }
                });
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        // 等待所有任务完成,这里设置了最长等待时间为1小时
        try{
            executorService.awaitTermination(1, TimeUnit.HOURS);
        } catch (InterruptedException e){
            // 如果当线程在等待是被中断,立即关闭线程池
            System.out.println("线程池中断了,立即关闭");
            executorService.shutdown();
        }
        
        // 关闭线程池
        executorService.shutdown();;
    }
;