Is there any way to schedule CompletableFuture in Java? What I wanted to do is to schedule a task to be executed with some delay, and chain it with other operations to be performed asynchronously when it completes. So far I didn't find any way to do this.
For good ol' Futures we have e.g. ScheduledExecutorService, where we can schedule a task to be executed with some delay like this:
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
Future<String> future = scheduledExecutorService.schedule(() -> "someValue", 10, TimeUnit.SECONDS);
Is there any similar way for CompletableFutures?
As said, there is support in Java 9.
But it’s not hard to create a similar feature under Java 8; you already named the necessary elements:
// prefer this constructor with zero core threads for a shared pool,
// to avoid blocking JVM exit
static final ScheduledExecutorService SCHEDULER = new ScheduledThreadPoolExecutor(0);
static Executor delayedExecutor(long delay, TimeUnit unit)
{
return delayedExecutor(delay, unit, ForkJoinPool.commonPool());
}
static Executor delayedExecutor(long delay, TimeUnit unit, Executor executor)
{
return r -> SCHEDULER.schedule(() -> executor.execute(r), delay, unit);
}
which can be used similarly to the Java 9 feature:
Executor afterTenSecs = delayedExecutor(10L, TimeUnit.SECONDS);
CompletableFuture<String> future
= CompletableFuture.supplyAsync(() -> "someValue", afterTenSecs);
future.thenAccept(System.out::println).join();
Care must be taken to avoid that the shared scheduled executor’s threads prevent the JVM from terminating. The alternative to a zero core pool size is to use daemon threads:
static final ScheduledExecutorService SCHEDULER
= Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
});
If you're using Java 9+ then CompletableFuture#delayedExecutor(long,TimeUnit)
may fit your needs:
Returns a new Executor that submits a task to the default executor after the given delay (or no delay if non-positive). Each delay commences upon invocation of the returned executor's
execute
method.
Executor delayed = CompletableFuture.delayedExecutor(10L, TimeUnit.SECONDS);
CompletableFuture.supplyAsync(() -> "someValue", delayed)
.thenAccept(System.out::println)
.join();
There's also an overload where you can specify the Executor
to use in place of the "default executor".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With