Java Multithreaded Progress Class for Real‑Time Performance Test Monitoring
This article introduces a Java multithreaded Progress class that asynchronously collects and displays performance test progress for both fixed‑thread and fixed‑QPS models, explains its design, provides usage examples, and shows sample console output.
During long‑running performance tests it is often hard to control or monitor the test progress. To solve this, the author created a multithreaded Java class that asynchronously gathers and outputs the progress of performance tests.
The design supports two test models—fixed thread count and fixed QPS—as well as two execution modes—time‑based and count‑based. Different flags are used to distinguish the models, and the appropriate limit (time or count) is retrieved to calculate the progress, which is then displayed using the same block‑style visual indicator described in a previous article.
package com.fun.frame.execute;
import com.fun.base.constaint.FixedQpsThread;
import com.fun.base.constaint.ThreadBase;
import com.fun.base.constaint.ThreadLimitTimeCount;
import com.fun.base.constaint.ThreadLimitTimesCount;
import com.fun.base.exception.ParamException;
import com.fun.config.HttpClientConstant;
import com.fun.frame.SourceCode;
import com.fun.utils.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 用于异步展示性能测试进度的多线程类
*/
public class Progress extends SourceCode implements Runnable {
private static Logger logger = LoggerFactory.getLogger(Progress.class);
private boolean st = true; // total switch
public boolean isTimesMode;
private ThreadBase base;
private int limit;
private long startTime = Time.getTimeStamp();
private String taskDesc;
public Progress(ThreadBase base, String desc) {
this(base);
this.base = base;
this.taskDesc = desc;
}
private Progress(ThreadBase base) {
if (base instanceof ThreadLimitTimeCount) {
this.isTimesMode = false;
this.limit = ((ThreadLimitTimeCount) base).time;
} else if (base instanceof ThreadLimitTimesCount) {
this.isTimesMode = true;
this.limit = ((ThreadLimitTimesCount) base).times;
} else if (base instanceof FixedQpsThread) {
FixedQpsThread fix = (FixedQpsThread) base;
this.isTimesMode = fix.isTimesMode;
this.limit = fix.limit;
} else {
ParamException.fail("创建进度条对象失败!");
}
}
@Override
public void run() {
int pro = 0;
while (st) {
sleep(HttpClientConstant.LOOP_INTERVAL);
if (isTimesMode) {
pro = (int) (base.executeNum * 1.0 / limit * BUCKET_SIZE * 2);
} else {
pro = (int) ((Time.getTimeStamp() - startTime) * 1.0 / limit * BUCKET_SIZE * 2);
}
if (pro >= BUCKET_SIZE * 2) break;
logger.info("{}测试进度:{} {}", taskDesc, getManyString(getPercent(8), pro), getPercent(getPercent(BUCKET_SIZE * 2, pro)));
}
}
/**
* 关闭线程,防止死循环
*/
public void stop() {
st = false;
logger.info("{}测试进度:{} {}", taskDesc, getManyString(getPercent(8), BUCKET_SIZE * 2), "100%");
}
}The class is used in a demo where a Progress instance is created before starting the test threads, a new Thread is launched to run it, and after all test threads finish the stop() method is called to finalize the progress display.
/**
* 执行多线程任务
* 默认取list中thread对象,丢入线程池,完成多线程执行,如果没有threadname,name默认采用desc+线程数作为threadname,去除末尾的日期
*/
public PerformanceResultBean start() {
Progress progress = new Progress(threads.get(0), desc.replaceAll("\\d{14}$", EMPTY));
new Thread(progress).start();
startTime = Time.getTimeStamp();
for (int i = 0; i < threadNum; i++) {
ThreadBase thread = threads.get(i);
if (StringUtils.isBlank(thread.threadName)) thread.threadName = desc.replaceAll("\\d{14}$", EMPTY) + i;
thread.setCountDownLatch(countDownLatch);
executorService.execute(thread);
}
shutdownService(executorService, countDownLatch);
endTime = Time.getTimeStamp();
progress.stop();
threads.forEach(x -> {
if (x.status()) failTotal++;
errorTotal += x.errorNum;
executeTotal += x.executeNum;
});
logger.info("总计{}个线程,共用时:{} s,执行总数:{},错误数:{},失败数:{}", threadNum, Time.getTimeDiffer(startTime, endTime), executeTotal, errorTotal, failTotal);
return over();
}Sample console output demonstrates the incremental progress bar with percentage values, e.g., "教学活动列表测试进度:██ 4.34%" progressing up to 100%.
Source code repositories are provided on Gitee (https://gitee.com/fanapi/tester) and GitHub (https://github.com/JunManYuanLong/FunTester) for readers to explore further.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
