Understanding Java CountDownLatch: Introduction, Core Methods, and Practical Usage
This article explains Java’s CountDownLatch class, covering its package location, constructor, essential await and countDown methods, and demonstrates practical integration within a multithreaded performance testing framework, including sample code for task execution, thread management, and cleanup.
The CountDownLatch class resides in the java.util.concurrent package and provides a simple counting mechanism useful for coordinating multiple threads, such as waiting for a set of tasks to finish before proceeding.
Basic Introduction
The class offers a single constructor that takes an int representing the initial count of the latch.
/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
**/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}Key Methods
The most commonly used methods are two await overloads—one without timeout and one with timeout control—and the countDown method that decrements the counter.
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void countDown() {
sync.releaseShared(1);
}Practical Usage
Below is an example of how the latch is used in a performance testing framework to coordinate task execution across multiple threads.
/**
* Execute multithreaded task
**/
public PerformanceResultBean start() {
startTime = Time.getTimeStamp();
for (int i = 0; i < threadNum; i++) {
ThreadBase thread = getThread(i);
thread.setCountDownLatch(countDownLatch);
executorService.execute(thread);
}
shutdownService(executorService, countDownLatch);
endTime = Time.getTimeStamp();
threads.forEach(x -> {
if (x.status()) failTotal++;
errorTotal += x.errorNum;
excuteTotal += x.excuteNum;
});
logger.info("总计{}个线程,共用时:{} s,执行总数:{},错误数:{},失败数:{}", threadNum, Time.getTimeDiffer(startTime, endTime), excuteTotal, errorTotal, failTotal);
return over();
}The multithread base class defines a run() method that repeatedly performs work, records timing, handles errors, and respects timeout or stop conditions.
@Override
public void run() {
try {
before();
List<Long> t = new ArrayList<>();
long ss = Time.getTimeStamp();
long et = ss;
while (true) {
try {
threadmark = mark == null ? EMPTY : this.mark.mark(this);
long s = Time.getTimeStamp();
doing();
et = Time.getTimeStamp();
excuteNum++;
long diff = et - s;
t.add(diff);
if (diff > HttpClientConstant.MAX_ACCEPT_TIME) marks.add(diff + CONNECTOR + threadmark);
if ((et - ss) > time || status() || key) break;
} catch (Exception e) {
logger.warn("执行任务失败!", e);
logger.warn("执行失败对象的标记:{}", threadmark);
errorNum++;
}
long ee = Time.getTimeStamp();
logger.info("执行次数:{}, 失败次数: {},总耗时: {} s", excuteNum, errorNum, (ee - ss) / 1000 + 1);
Concurrent.allTimes.addAll(t);
Concurrent.requestMark.addAll(marks);
}
} catch (Exception e) {
logger.warn("执行任务失败!", e);
} finally {
after();
}
}The after() method cleans up resources after execution.
@Override
protected void after() {
super.after();
marks = new ArrayList<>();
GCThread.stop();
}This tutorial was originally published on the FunTester WeChat public account.
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.
