From e3292d8acd22be3f55d802df2facde6565256e6e Mon Sep 17 00:00:00 2001 From: ZZX9599 <536509593@qq.com> Date: Mon, 29 Sep 2025 17:35:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B9=B6=E5=8F=91=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/ConcurrentHttpRequestTest.java | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/main/java/com/yj/earth/common/util/ConcurrentHttpRequestTest.java diff --git a/src/main/java/com/yj/earth/common/util/ConcurrentHttpRequestTest.java b/src/main/java/com/yj/earth/common/util/ConcurrentHttpRequestTest.java new file mode 100644 index 0000000..dc3e3ce --- /dev/null +++ b/src/main/java/com/yj/earth/common/util/ConcurrentHttpRequestTest.java @@ -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("=========================================================="); + } +}