Accelerating Multi‑User Performance Tests with Java’s CyclicBarrier
This article explains how to eliminate the serial‑login bottleneck in multi‑user performance testing by using Java’s CyclicBarrier to synchronize user logins, then runs a two‑step insert‑update scenario with a custom FunTester class, complete with full code examples and result analysis.
Background
In earlier performance‑test designs the author logged each user sequentially, stored a Base object, and then passed it to a multithreaded task. This caused long waiting times when many threads were used because logins were performed one after another.
Solution with CyclicBarrier
The author introduces CyclicBarrier to synchronize the login step across all threads. All threads reach the barrier after logging in; only then does the actual test method start, eliminating the serial‑login bottleneck.
Test Case Design
The scenario requires two steps: insert a record with a unique identifier and then update its status. By combining the insert and update in a single linked‑performance test, the need for separate data‑creation steps is avoided.
Implementation Details
Key classes: ThreadLimitTimesCount<Integer> – a base class that limits thread count and execution times.
Inner static class FunTester extends the base class and holds an Order object and a CyclicBarrier.
In before() the thread creates the Order instance and calls cyclicBarrier.await(). In doing() it generates a unique orderNum, creates the order, and then calls order.refund(orderNum).
@Override
protected void doing() {
String orderNum = "FunTester" + getMark() + StringUtil.getString(10);
threadmark += orderNum;
order.insert(orderNum);
order.update(orderNum);
} private static class FunTester extends ThreadLimitTimesCount<Integer> {
Order order;
CyclicBarrier cyclicBarrier;
FunTester(int u, int times, CyclicBarrier cyclicBarrier) {
super(u, times, null);
this.cyclicBarrier = cyclicBarrier;
}
@Override
void before() {
super.before();
this.order = new Order(getBase(t));
cyclicBarrier.await();
}
@Override
protected void doing() {
String orderNum = "f" + getMark() + StringUtil.getString(5);
threadmark += orderNum;
order.create(101, "FunTester测试课程", 13120454219L, 10, 10, orderNum);
order.refund(orderNum);
}
}Test Script
The main method configures the number of threads, creates a CyclicBarrier with a runnable that logs “All accounts logged in, starting test!”, builds a list of FunTester instances, and runs them through a Concurrent executor.
static void main(String[] args) {
Common.notPrintResponse();
ClientManage.init(10, 5, 0, EMPTY, 0);
def argsUtil = new ArgsUtil(args);
def thread = argsUtil.getIntOrdefault(0, 10);
def times = argsUtil.getIntOrdefault(1, 10);
def threads = [];
CyclicBarrier cyclicBarrier = new CyclicBarrier(thread, new Runnable() {
@Override
void run() {
logger.info("所有账号登录完成!,即将开始测试!");
}
});
thread.times {
threads << new FunTester(it, times, cyclicBarrier);
}
new Concurrent(threads, "一个不可描述的用例场景").start();
FunLibrary.testOver();
}Result Logging
The console prints login information, request latency, and a final JSON summary containing total requests, QPS, error rate, and execution time. Because the data set is small, the charting step is skipped.
INFO-> 当前用户:fv,IP:10.60.193.37,工作目录:/Users/fv/Documents/workspace/qa/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO-> 本校共有:627名老师,852名学生,11个班级!
INFO-> 请求uri:不可描述的地址/login,耗时:458 ms, requestId:Fun20210310111251QvEl
... (omitted repetitive logs) ...
INFO-> 所有账号登录完成!,即将开始测试!
... (test summary) ...
{"rt":210,"total":100,"qps":47.619,"failRate":0.0,"threads":10,"startTime":"2021-03-10 11:12:51","endTime":"2021-03-10 11:12:54","errorRate":0.0,"executeTotal":100,"mark":"一个不可描述的用例场景101112","table":"eJwBHQDi/+aVsOaNrumHj+WkquWwkSzml6Dms5Xnu5jlm74hMCkTtQ=="}
INFO-> 数据量太少,无法绘图!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.
