是否可以安排 CompletableFuture?

Łuk*_*uba 12 java concurrency scheduled-tasks completable-future

有没有办法在 Java 中安排 CompletableFuture?我想要做的是安排一个要延迟执行的任务,并在它完成时将它与其他要异步执行的操作链接起来。到目前为止,我没有找到任何方法来做到这一点。

对于好的 ol' Futures,我们有例如 ScheduledExecutorService,我们可以在其中安排一个任务以延迟执行,如下所示:

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
Future<String> future = scheduledExecutorService.schedule(() -> "someValue", 10, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)

CompletableFutures 有没有类似的方法?

Hol*_*ger 10

如前所述,Java 9 提供支持。

但是在 Java 8 下创建一个类似的特性并不难;您已经命名了必要的元素:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

它可以类似于 Java 9 功能使用:

Executor afterTenSecs = delayedExecutor(10L, TimeUnit.SECONDS);
CompletableFuture<String> future 
  = CompletableFuture.supplyAsync(() -> "someValue", afterTenSecs);

future.thenAccept(System.out::println).join();
Run Code Online (Sandbox Code Playgroud)

必须小心避免共享调度执行器的线程阻止 JVM 终止。零核心池大小的替代方案是使用守护线程:

static final ScheduledExecutorService SCHEDULER
  = Executors.newSingleThreadScheduledExecutor(r -> {
    Thread t = new Thread(r);
    t.setDaemon(true);
    return t;
  });
Run Code Online (Sandbox Code Playgroud)

  • @Woodz,我这边有一个失误,当然,可运行程序应该在经过时间后在指定的执行器上执行,而不是“ScheduledThreadPoolExecutor”。 (2认同)
  • @Spring 当您提交给延迟执行器时,您可以立即继续执行其他操作。当您在提交之前使用“睡眠”时,您将阻塞启动线程。相反,当您在实际操作中包含“睡眠”时,您将阻塞本来可以处理不同作业的工作线程。当您只执行一次和/或没有其他工作要处理时,两者都无关紧要,但当您执行多次时,可能会降低性能。此外,当所有工作线程都被“睡眠”阻塞时,可能会发生另一个应该早于睡眠线程运行的作业无法运行的情况。 (2认同)

Sla*_*law 9

如果您使用的是 Java 9+,那么CompletableFuture#delayedExecutor(long,TimeUnit)可能会满足您的需求:

返回一个新的 Executor,它在给定的延迟后(如果非正则不延迟)将任务提交给默认执行器。每个延迟都在调用返回的执行程序execute方法时开始。

Executor delayed = CompletableFuture.delayedExecutor(10L, TimeUnit.SECONDS);
CompletableFuture.supplyAsync(() -> "someValue", delayed)
    .thenAccept(System.out::println)
    .join();
Run Code Online (Sandbox Code Playgroud)

还有一个重载,您可以在其中指定Executor要使用的代替“默认执行程序”。