Java案例如何实现压力测试?

wen java案例 57

本文目录导读:

Java案例如何实现压力测试?

  1. 方法一:使用 Java 原生并发工具(模拟高并发)
  2. 方法二:压测 REST API(使用 HttpClient)
  3. 方法三:使用专业工具(推荐)
  4. 方法四:使用 Java + JMH(微基准测试)
  5. 压测实战建议

在Java中实现压力测试,通常有几种成熟的方法:使用专业工具(如JMeter、Gatling)、使用Java原生并发工具(如ExecutorServiceCountDownLatch)、或是结合HTTP客户端(如OkHttp、Apache HttpClient)进行自定义测试。

下面我会提供最常用、最典型的几种实现案例,涵盖Web接口压测方法级压测


使用 Java 原生并发工具(模拟高并发)

这是最基础、最灵活的方式,适合测试某个具体方法或系统接口的瓶颈。

案例:使用 CountDownLatch + ExecutorService 模拟高并发请求

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class SimpleStressTest {
    // 模拟要压测的服务
    static class MyService {
        public String process(String request) {
            try {
                // 模拟业务处理耗时 (50ms)
                Thread.sleep(50);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "processed: " + request;
        }
    }
    public static void main(String[] args) throws InterruptedException {
        final int concurrency = 100; // 并发线程数
        final int totalRequests = 1000; // 总请求数
        MyService service = new MyService();
        ExecutorService executor = Executors.newFixedThreadPool(concurrency);
        // 计数器:所有线程都准备好后同时发起请求
        CountDownLatch readyLatch = new CountDownLatch(concurrency);
        // 计数器:所有请求执行完后主线程继续
        CountDownLatch endLatch = new CountDownLatch(totalRequests);
        AtomicInteger successCount = new AtomicInteger(0);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < totalRequests; i++) {
            final int requestId = i;
            executor.submit(() -> {
                try {
                    readyLatch.countDown(); // 报告准备就绪
                    readyLatch.await();     // 等待所有线程准备就绪(实现“齐射”效果)
                    // 执行请求
                    service.process("req-" + requestId);
                    successCount.incrementAndGet();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    endLatch.countDown();
                }
            });
        }
        // 等待所有请求完成
        endLatch.await();
        long endTime = System.currentTimeMillis();
        executor.shutdown();
        // 输出结果
        long totalTime = endTime - startTime;
        double tps = (double) totalRequests / (totalTime / 1000.0);
        System.out.println("总耗时: " + totalTime + " ms");
        System.out.println("成功请求数: " + successCount.get());
        System.out.println("QPS (TPS): " + String.format("%.2f", tps));
    }
}

运行效果
并发 100 个线程,共 1000 次调用,输出如:
总耗时: 5523 ms
QPS (TPS): 181.05


压测 REST API(使用 HttpClient)

如果你的目标是压测一个真正的 HTTP 接口,Spring Boot 应用,可以用以下案例。

依赖(Maven)

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version>
</dependency>

代码实现:并发调用远程 HTTP 接口

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class HttpStressTest {
    public static void main(String[] args) throws InterruptedException {
        String url = "http://localhost:8080/api/test"; // 替换为你的接口
        int concurrency = 50;
        int totalRequests = 500;
        ExecutorService executor = Executors.newFixedThreadPool(concurrency);
        CountDownLatch startLatch = new CountDownLatch(1); // 统一开始
        CountDownLatch endLatch = new CountDownLatch(totalRequests);
        AtomicInteger success = new AtomicInteger(0);
        AtomicInteger failure = new AtomicInteger(0);
        for (int i = 0; i < totalRequests; i++) {
            executor.submit(() -> {
                try {
                    startLatch.await(); // 等待主线程发令
                    try (CloseableHttpClient httpClient = HttpClients.createDefault();
                         CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {
                        if (response.getCode() == 200) {
                            success.incrementAndGet();
                        } else {
                            failure.incrementAndGet();
                        }
                    } catch (Exception e) {
                        failure.incrementAndGet();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    endLatch.countDown();
                }
            });
        }
        long startTime = System.currentTimeMillis();
        startLatch.countDown(); // 发令:所有线程同时开始
        endLatch.await();       // 等待所有请求完成
        long endTime = System.currentTimeMillis();
        executor.shutdown();
        System.out.println("总耗时: " + (endTime - startTime) + " ms");
        System.out.println("成功: " + success.get() + ", 失败: " + failure.get());
        System.out.println("QPS: " + String.format("%.2f", totalRequests / ((endTime - startTime) / 1000.0)));
    }
}

使用专业工具(推荐)

虽然上面都是纯 Java 实现,但在生产环境或正式压测中,强烈建议使用专门的压力测试工具,它们提供更丰富的报告、更强大的并发控制。

工具 特点 适用场景
JMeter 图形化界面,支持多种协议,插件丰富 一般压测需求
Gatling Scala 编写,高性能,生成 HTML 报告美观 持续集成、DevOps 场景
ab (Apache Bench) 命令行工具,简单快速 快速验证
wrk / wrk2 C 编写,极高并发能力 高性能测试

💡 快速使用 ab 压测

# 安装 (Mac)
brew install ab
# 压测:100 并发,共 1000 请求
ab -n 1000 -c 100 http://localhost:8080/api/test

输出包含:Requests per second(QPS)、Time per requestTransfer rate 等关键指标。


使用 Java + JMH(微基准测试)

如果你的目标是压测单个方法的性能(而非完整的 HTTP 请求链),请使用 JMH(Java Microbenchmark Harness)。

示例代码(简化)

@BenchmarkMode(Mode.Throughput) // 吞吐量
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
public class MyBenchmark {
    @Benchmark
    public void testMethod() {
        // 这里放你要测试的方法
        MyService service = new MyService();
        service.process("test");
    }
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(MyBenchmark.class.getSimpleName())
                .forks(1)
                .warmupIterations(3)
                .measurementIterations(5)
                .threads(4)
                .build();
        new Runner(opt).run();
    }
}

注意:JMH 适合 微基准,不适合压测数据库或外部网络依赖。


压测实战建议

  1. 配置 JVM 参数
    压测时,注意调整堆内存、GC 策略,避免被 GC 干扰结果。

    -Xms2g -Xmx2g -XX:+UseG1GC
  2. 预留预热期
    JVM 有 JIT 编译和类加载,压测前先“预热”几次(Warm-up),使数据有效。

  3. 监控系统资源
    使用 topjstatVisualVM 观察 CPU、内存、GC 情况,发现瓶颈。

  4. 分布式压测
    单机性能有限,需压测上万并发时,考虑 JMeter 分布式、Gatling 集群。


场景 推荐方式
快速验证单个方法性能 Java 原生并发 + CountDownLatch
压测 REST API 上面的 HttpStressTest + 适当提高并发
专业级 HTTP 压测 JMeter (GUI友好) 或 Gatling (代码驱动)
微基准测试 JMH
命令行快速调试 ab 或 wrk

如果你能提供更具体的需求(如:压测数据库连接池、WebSocket、gRPC),我可以给出针对性的案例。

抱歉,评论功能暂时关闭!