并发测试

This commit is contained in:
ZZX9599
2025-09-29 17:35:03 +08:00
parent efe4ddf97b
commit e3292d8acd

View File

@ -0,0 +1,152 @@
package com.yj.earth.common.util;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 并发HTTP请求测试工具
* 目标地址192.168.110.25:8848/modelLibrary/data/model/1066/glb
*/
public class ConcurrentHttpRequestTest {
// ====================== 测试参数配置(可根据需求调整)======================
// 目标请求URL
private static final String TARGET_URL = "http://192.168.110.25:8848/modelLibrary/data/model/1066/glb";
// 并发线程数如模拟100个并发设置为100
private static final int CONCURRENT_THREADS = 50;
// 每个线程发送的请求次数如每个线程发10次总请求数=50*10=500
private static final int REQUESTS_PER_THREAD = 10;
// HTTP请求超时时间毫秒
private static final int HTTP_CONNECT_TIMEOUT = 3000;
private static final int HTTP_READ_TIMEOUT = 5000;
// ====================== 统计指标(线程安全)======================
// 成功请求数
private static final AtomicInteger SUCCESS_COUNT = new AtomicInteger(0);
// 失败请求数
private static final AtomicInteger FAIL_COUNT = new AtomicInteger(0);
// 总耗时(毫秒)
private static long TOTAL_TIME = 0;
public static void main(String[] args) {
System.out.println("===================== 并发请求测试开始 =====================");
System.out.printf("测试配置:并发线程数=%d单线程请求数=%d总请求数=%d%n",
CONCURRENT_THREADS, REQUESTS_PER_THREAD, CONCURRENT_THREADS * REQUESTS_PER_THREAD);
System.out.printf("目标URL%s%n", TARGET_URL);
System.out.println("----------------------------------------------------------");
// 1. 初始化OkHttp客户端复用连接池减少连接创建开销
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(HTTP_READ_TIMEOUT, TimeUnit.MILLISECONDS)
.connectionPool(new okhttp3.ConnectionPool(
50, // 最大空闲连接数(建议不小于并发线程数)
5, TimeUnit.MINUTES // 连接空闲超时
))
.build();
// 2. 初始化线程池(固定线程数,匹配并发需求)
ExecutorService executorService = Executors.newFixedThreadPool(CONCURRENT_THREADS);
// 倒计时锁:等待所有线程执行完成
CountDownLatch countDownLatch = new CountDownLatch(CONCURRENT_THREADS);
// 3. 记录测试开始时间
long startTime = System.currentTimeMillis();
// 4. 提交并发任务(每个任务对应一个线程)
for (int i = 0; i < CONCURRENT_THREADS; i++) {
int threadIndex = i + 1; // 线程编号(方便日志区分)
executorService.submit(() -> {
try {
// 单个线程执行指定次数的请求
for (int j = 0; j < REQUESTS_PER_THREAD; j++) {
int requestIndex = j + 1; // 请求编号
sendRequest(okHttpClient, threadIndex, requestIndex);
}
} finally {
// 线程任务完成倒计时减1
countDownLatch.countDown();
}
});
}
// 5. 等待所有线程完成(阻塞直到所有任务结束)
try {
countDownLatch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("测试被中断:" + e.getMessage());
}
// 6. 计算测试结果
long endTime = System.currentTimeMillis();
TOTAL_TIME = endTime - startTime;
printTestResult();
// 7. 释放资源
executorService.shutdown();
okHttpClient.connectionPool().evictAll(); // 清空连接池
}
/**
* 发送单个HTTP GET请求
* @param okHttpClient OkHttp客户端复用
* @param threadIndex 线程编号
* @param requestIndex 该线程内的请求编号
*/
private static void sendRequest(OkHttpClient okHttpClient, int threadIndex, int requestIndex) {
// 构建请求若需要Headers可在此处添加如Token、Cookie等
Request request = new Request.Builder()
.url(TARGET_URL)
.get() // GET请求目标接口是GET无需Body
.build();
long requestStartTime = System.currentTimeMillis();
try (Response response = okHttpClient.newCall(request).execute()) {
// 判定请求成功响应码200-299且响应体非空根据你的接口实际情况调整
if (response.isSuccessful() && response.body() != null) {
// 读取响应体(避免连接泄漏,即使不需要内容也建议读取后关闭)
byte[] responseBody = response.body().bytes();
long requestCostTime = System.currentTimeMillis() - requestStartTime;
SUCCESS_COUNT.incrementAndGet();
System.out.printf("[线程%d-请求%d] 成功 | 响应码:%d | 响应体大小:%dB | 耗时:%dms%n",
threadIndex, requestIndex, response.code(), responseBody.length, requestCostTime);
} else {
// 响应码非成功如404、500
FAIL_COUNT.incrementAndGet();
System.err.printf("[线程%d-请求%d] 失败 | 响应码:%d | 原因:%s%n",
threadIndex, requestIndex, response.code(), response.message());
}
} catch (Exception e) {
// 网络异常超时、连接拒绝、IO错误等
FAIL_COUNT.incrementAndGet();
System.err.printf("[线程%d-请求%d] 异常 | 原因:%s%n",
threadIndex, requestIndex, e.getMessage());
}
}
/**
* 打印测试结果(核心指标统计)
*/
private static void printTestResult() {
System.out.println("==========================================================");
System.out.println("===================== 测试结果汇总 =====================");
int totalRequests = SUCCESS_COUNT.get() + FAIL_COUNT.get();
double successRate = totalRequests == 0 ? 0 : (SUCCESS_COUNT.get() * 100.0) / totalRequests;
double avgTimePerRequest = totalRequests == 0 ? 0 : (TOTAL_TIME * 1.0) / totalRequests;
double qps = totalRequests == 0 ? 0 : (totalRequests * 1000.0) / TOTAL_TIME; // 每秒请求数
System.out.printf("总请求数:%d%n", totalRequests);
System.out.printf("成功请求数:%d | 失败请求数:%d%n", SUCCESS_COUNT.get(), FAIL_COUNT.get());
System.out.printf("成功率:%.2f%%%n", successRate);
System.out.printf("总耗时:%dms%n", TOTAL_TIME);
System.out.printf("平均请求耗时:%.2fms%n", avgTimePerRequest);
System.out.printf("QPS每秒请求数%.2f%n", qps);
System.out.println("==========================================================");
}
}