问题描述
我正在玩 Java 8 可完成的期货.我有以下代码:
I am playing with Java 8 completable futures. I have the following code:
CountDownLatch waitLatch = new CountDownLatch(1);
CompletableFuture<?> future = CompletableFuture.runAsync(() -> {
try {
System.out.println("Wait");
waitLatch.await(); //cancel should interrupt
System.out.println("Done");
} catch (InterruptedException e) {
System.out.println("Interrupted");
throw new RuntimeException(e);
}
});
sleep(10); //give it some time to start (ugly, but works)
future.cancel(true);
System.out.println("Cancel called");
assertTrue(future.isCancelled());
assertTrue(future.isDone());
sleep(100); //give it some time to finish
使用 runAsync 我安排了一个等待闩锁的代码的执行.接下来我取消未来,期望在里面抛出一个被中断的异常.但似乎线程在 await 调用上仍然被阻塞,并且即使未来被取消(断言通过)也永远不会抛出 InterruptedException.使用 ExecutorService 的等效代码按预期工作.这是 CompletableFuture 中的错误还是我的示例中的错误?
Using runAsync I schedule execution of a code that waits on a latch. Next I cancel the future, expecting an interrupted exception to be thrown inside. But it seems that the thread remains blocked on the await call and the InterruptedException is never thrown even though the future is canceled (assertions pass). An equivalent code using ExecutorService works as expected. Is it a bug in the CompletableFuture or in my example?
推荐答案
显然,这是有意为之.方法的 Javadoc CompletableFuture::cancel 状态:
Apparently, it's intentional. The Javadoc for the method CompletableFuture::cancel states:
[Parameters:] mayInterruptIfRunning - 此值在此实现中没有影响,因为中断不用于控制处理.
有趣的是,方法 ForkJoinTask::cancel 对参数 mayInterruptIfRunning 使用几乎相同的措辞.
Interestingly, the method ForkJoinTask::cancel uses almost the same wording for the parameter mayInterruptIfRunning.
我对这个问题有一个猜测:
I have a guess on this issue:
- 中断旨在与阻塞操作一起使用,例如sleep、wait或I/O操作,
- 但 CompletableFuture 和 ForkJoinTask 均不打算与阻塞操作一起使用.
- interruption is intended to be used with blocking operations, like sleep, wait or I/O operations,
- but neither CompletableFuture nor ForkJoinTask are intended to be used with blocking operations.
CompletableFuture 应该创建一个新的 CompletionStage 而不是阻塞,而 cpu 绑定任务是 fork-join 模型的先决条件.因此,对它们中的任何一个使用 interruption 都会破坏它们的目的.另一方面,它可能会增加复杂性,如果按预期使用则不需要.
Instead of blocking, a CompletableFuture should create a new CompletionStage, and cpu-bound tasks are a prerequisite for the fork-join model. So, using interruption with either of them would defeat their purpose. And on the other hand, it might increase complexity, that's not required if used as intended.
这篇关于如何取消 Java 8 可完成的未来?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!