0

I am using a CountDownLatch to wait for N operations to complete before executing some code, whilst giving a timeout to make sure that the final code gets executed even if not all N operations are completed. i.e:

    CountDownLatch latch= new CountDownLatch(N);
    latch.await(20, TimeUnit.MINUTES);
    //Some code 

I would like the 20 minutes timeout to be dynamic, so that it is reset each time the latch gets a countdown, so the latch will exit the await only if 20 minutes has passed since the last time it got a countdown (or the normal case ofcourse, when it recieves N countdowns). Is this supported in any way?

iddqd
  • 1,225
  • 2
  • 16
  • 34

1 Answers1

0

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();
            }
        }
    }
}
jjcipher
  • 147
  • 1
  • 2
  • 7