How to invoke some code once after and additional to a Thread.sleep

Viewed 73

Imagine having this code running in a Thread:

while (blockingQueue.size() > 0) {
    
    AbortableCountDownLatch latch = (AbortableCountDownLatch) blockingQueue.poll();
    latch.countDown();
}
Thread.sleep(updateinterval * 1000);

How to make the while loop run after the Thread.sleep as an additional execution? As something like:

Thread.sleepAndExecute(Runnable code, sleep time);

So that the code is just executed, after the sleep has entered, not the other way around?

The blockingQueue contains some CountDownLatch, which are blocking another thread. The other thread just is allowed to continue, IF the latches are all countdown AND this thread has entered sleep/await state. Both conditions need to be true so that the other thread is allowed to continue.

3 Answers

The point is that you should not be needing to sleep. You can use CompleteableFurture API thenCombine to combine the two tasks. Code below

        CompletableFuture.runAsync(() -> {
            while (blockingQueue.size() > 0) {
                try {
                   System.out.println("Sleeping in thread - " + Thread.currentThread().getName());
                   Thread.sleep(1000l);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        })
        .thenCombine( CompletableFuture.runAsync( () -> {
            System.out.println("Polling in thread - " + Thread.currentThread().getName());
            while (blockingQueue.size() > 0) {

                AbortableCountDownLatch latch = blockingQueue.poll();
                latch.countDown();
            }
        }), (i, j) -> null);

Both sleep and latchdown happens in different threads.

Sleeping in thread - ForkJoinPool.commonPool-worker-19
Polling in thread - ForkJoinPool.commonPool-worker-5
Sleeping in thread - ForkJoinPool.commonPool-worker-19

CompletionStages implements producer-consumer with the help of two stages chained using *Async API and passing the executor with blocking queue. I think that should be the best fit for your use case.

You may want to use CompletableFuture's thenApply method as a callback to supplyAsync.

As the name suggests, supplyAsync takes a Supplier<T> as an argument, while thenApply takes a Function<T,R>:

CompletableFuture<String> futureText = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
       throw new IllegalStateException(e);
    }
    return "waited one second";
}).thenApply(input-> {
    // run some code as an additional execution
    return "inside thenApply, " + input;
});

System.out.println(futureText.get()); // prints: inside thenApply, waited one second

You need to add sleep in a different thread. Either you can use completeable future or Executor Service.

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit( () -> {
            try {
                Thread.sleep(1000l);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        while (blockingQueue.size() > 0) {

            AbortableCountDownLatch latch = blockingQueue.poll();
            latch.countDown();
        }
        executorService.shutdown();
Related