CountDownLatch具有动态超时

时间:2017-11-23 09:56:10

标签: java synchronization countdown countdownlatch

我正在使用CountDownLatch在执行某些代码之前等待N个操作完成,同时给出超时以确保即使并非所有N个操作都已完成也会执行最终代码。 即:

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

我希望20分钟超时是动态的,因此每次锁存器倒计时都会重置,所以只有在自上次倒计时20分钟后锁存器才会退出等待(或者正常的情况,当它收到N次倒计时)。这有什么支持吗?

1 个答案:

答案 0 :(得分:0)

您可以在自己的CountDownLatch中实施此功能。您可以保留调用方法countDown()的时间戳,将其与等待开始时的时间戳进行比较,调整等待时间,如果时间戳不同则再次等待。例如,

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;
        }
    }
}

这是一个测试程序:

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();
            }
        }
    }
}