You can implement this feature in your own CountDownLatch
. You can keep a timestamp of when the method countDown()
is called, compare it to the timestamp when the waiting was started, adjust the waiting time and wait again if the timestamps are different. For example,
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class MyCountDownLatch extends CountDownLatch {
private AtomicLong timestamp;
public MyCountDownLatch(int count) {
super(count);
timestamp = new AtomicLong(System.nanoTime());
}
@Override
public void countDown() {
super.countDown();
timestamp.set(System.nanoTime());
}
public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException {
long start = timestamp.get();
long diff = 0;
for (;;) {
boolean result = await(unit.toNanos(timeout) - diff, TimeUnit.NANOSECONDS);
if (timestamp.get() == start) return result;
start = timestamp.get();
diff = System.nanoTime() - start;
}
}
}
And here is a test program:
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) throws InterruptedException {
MyCountDownLatch latch = new MyCountDownLatch(3);
// Create three workers and give them different work time
Worker worker1 = new Worker("A", 1, latch);
Worker worker2 = new Worker("B", 3, latch);
Worker worker3 = new Worker("C", 5, latch);
List<Worker> workers = Arrays.asList(worker1, worker2, worker3);
// Start the workers
workers.forEach(Worker::start);
// Wait until the latch to count down to zero, or no countdown in
// 3 seconds.
boolean result = latch.waitFor(3, TimeUnit.SECONDS);
System.out.printf("%s | latch.waitFor() returns %b\n", LocalTime.now(), result);
// Terminate those workers who are still running
workers.stream().filter(Worker::isAlive).forEach(Worker::interrupt);
}
static class Worker extends Thread {
private String name;
private int workTime;
private CountDownLatch latch;
public Worker(String name, int workTime, CountDownLatch latch) {
this.name = name;
this.workTime = workTime;
this.latch = latch;
}
@Override
public void run() {
try {
System.out.printf("%s | Worker %s started\n", LocalTime.now(), name);
Thread.sleep(workTime * 1000L);
System.out.printf("%s | Worker %s finished\n", LocalTime.now(), name);
} catch (InterruptedException e) {
System.out.printf("%s | Worker %s interrupted\n", LocalTime.now(), name);
} finally {
latch.countDown();
}
}
}
}