Enhancements to Marking, Recording, and Thread Initialization in a Performance Testing Framework
This article details recent updates to a performance testing framework, including moving the mark feature into ThreadBase, changing method signatures, introducing two virtual thread limit classes for count‑based and time‑based execution, optimizing after() handling, and abandoning deep‑copy cloning for thread objects.
The recent update focuses on the marking and recording functionalities as well as the initialization of the connection pool within a performance testing framework. The mark feature has been moved into ThreadBase, and the method signature now accepts ThreadBase instead of HttpRequestBase. Two virtual classes, ThreadLimitTimesCount and ThreadLimitTimeCount, replace the previous approach of overriding run() in concrete implementations, reducing bugs caused by method overriding.
Additional optimizations include improving how marked data is saved in the after() method to ensure thread‑safe and consistent storage, and abandoning deep‑copy cloning for thread objects because it creates complications when dealing with non‑cloneable types such as HttpRequestBase.
Key code snippets:
package com.fun.base.constaint;
import com.fun.base.interfaces.MarkThread;
import com.fun.frame.SourceCode;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
/**
* Multi‑thread task base class, can be used independently.
*/
public abstract class ThreadBase<T> extends SourceCode implements Runnable {
public int errorNum;
public int excuteNum;
protected CountDownLatch countDownLatch;
public MarkThread mark;
public T t;
protected ThreadBase() {}
public String getTString() { return t.toString(); }
protected abstract void before();
protected abstract void doing() throws Exception;
protected abstract void after();
public void setCountDownLatch(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; }
@Override
public ThreadBase clone() { return deepClone(this); }
public boolean status() { return false; }
public List<ThreadBase> multiply(int num) { return range(num).mapToObj(x -> this.clone()).collect(Collectors.toList()); }
} package com.fun.base.constaint;
import com.fun.base.interfaces.MarkThread;
import com.fun.config.HttpClientConstant;
import com.fun.frame.Save;
import com.fun.frame.excute.Concurrent;
import com.fun.frame.httpclient.GCThread;
import com.fun.utils.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
/**
* Thread class that limits execution by request count.
*/
public abstract class ThreadLimitTimesCount<T> extends ThreadBase<T> {
private static final Logger logger = LoggerFactory.getLogger(ThreadLimitTimesCount.class);
public List<String> marks = new ArrayList<>();
public static Vector<String> requestMark = new Vector<>();
private static boolean key = false;
public int times;
public ThreadLimitTimesCount(T t, int times, MarkThread markThread) {
this.times = times;
this.t = t;
this.mark = markThread;
}
protected ThreadLimitTimesCount() { super(); }
@Override
public void run() {
try {
before();
List<Long> t = new ArrayList<>();
long ss = Time.getTimeStamp();
for (int i = 0; i < times; i++) {
try {
String m = mark == null ? EMPTY : this.mark.mark(this);
long s = Time.getTimeStamp();
doing();
long e = Time.getTimeStamp();
long diff = e - s;
t.add(diff);
if (diff > HttpClientConstant.MAX_ACCEPT_TIME) marks.add(diff + CONNECTOR + m);
excuteNum++;
if (status() || key) break;
} catch (Exception e) {
logger.warn("执行任务失败!", e);
errorNum++;
}
}
long ee = Time.getTimeStamp();
logger.info("执行次数:{},错误次数: {},总耗时:{} s", times, errorNum, (ee - ss) / 1000 + 1);
Concurrent.allTimes.addAll(t);
} catch (Exception e) {
logger.warn("执行任务失败!", e);
} finally {
if (countDownLatch != null) countDownLatch.countDown();
after();
}
}
@Override
public void before() { key = false; }
@Override
public boolean status() { return errorNum > 10; }
public static void stopAllThread() { key = true; }
@Override
protected void after() {
requestMark.addAll(marks);
marks = new ArrayList<>();
GCThread.stop();
synchronized (this.getClass()) {
if (countDownLatch.getCount() == 0 && requestMark.size() != 0) {
Save.saveStringListSync(requestMark, MARK_Path.replace(LONG_Path, EMPTY) + Time.getDate().replace(SPACE_1, CONNECTOR));
requestMark = new Vector<>();
}
}
}
} package com.fun.frame.thead;
import com.fun.base.constaint.ThreadLimitTimesCount;
import com.fun.base.interfaces.MarkThread;
import com.fun.frame.httpclient.FanLibrary;
import com.fun.frame.httpclient.FunRequest;
import com.fun.frame.httpclient.GCThread;
import org.apache.http.client.methods.HttpRequestBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
/**
* HTTP request multithread class.
*/
public class RequestThreadTimes extends ThreadLimitTimesCount {
static Logger logger = LoggerFactory.getLogger(RequestThreadTimes.class);
public static Vector<String> requestMark = new Vector<>();
public HttpRequestBase request;
public List<String> marks = new ArrayList<>();
public RequestThreadTimes(HttpRequestBase request, int times) {
super(null, times, null);
this.request = request;
}
public RequestThreadTimes(HttpRequestBase request, int times, MarkThread mark) {
super(null, times, mark);
this.request = request;
}
protected RequestThreadTimes() { super(); }
@Override
public void before() { super.before(); GCThread.starts(); }
@Override
protected void doing() throws Exception { FanLibrary.excuteSimlple(request); }
@Override
public RequestThreadTimes clone() {
RequestThreadTimes threadTimes = new RequestThreadTimes();
threadTimes.times = this.times;
threadTimes.request = FunRequest.cloneRequest(request);
threadTimes.mark = mark.clone();
return threadTimes;
}
}The article also includes a disclaimer that the content was originally published on the “FunTester” public account and should not be reproduced without permission, followed by a curated list of other technical and non‑technical articles.
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.
