如何中断CompletableFuture的底层执行 [英] How to interrupt underlying execution of CompletableFuture
问题描述
我知道 CompletableFuture
设计不能通过中断来控制它的执行,但我想你们中的一些人可能会遇到这个问题。 CompletableFuture
是组合异步执行的非常好的方法,但考虑到你希望在取消未来时中断或停止底层执行的情况,我们该怎么做?或者我们必须接受任何取消或手动完成的 CompletableFuture
不会影响在那里完成它的线程吗?
<在我看来,这显然是一项无用的工作,需要时间来执行工人。我想知道在这种情况下哪种方法或设计可能会有所帮助?
更新
这是一个简单的测试
公共类SimpleTest {
@Test
public void testCompletableFuture()抛出异常{
CompletableFuture< Void> cf = CompletableFuture.runAsync(() - > longOperation());
bearSleep(1);
//cf.cancel(true);
cf.complete(null);
System.out.println(它现在应该已经死了);
bearSleep(7);
}
public static void longOperation(){
System.out.println(started);
bearSleep(5);
System.out.println(已完成);
}
private static void bearSleep(long seconds){
try {
TimeUnit.SECONDS.sleep(seconds);
} catch(InterruptedException e){
System.out.println(OMG !!! Interrupt !!!);
}
}
}
CompletableFuture
与最终可能完成它的异步操作无关。
因为(不像
FutureTask
)这个类没有直接控制导致它完成的
计算,取消被视为
只是另一种形式的例外完成。方法cancel
的
效果与completeExceptionally(new CancellationException())
。
甚至可能 一个单独的线程正在努力完成它(甚至可能很多工作的线程)。即使有,也没有从 CompletableFuture
链接到任何引用它的线程。
As这样,你无法通过 CompletableFuture
来中断任何可能正在运行某个任务的线程来完成它。您必须编写自己的逻辑来跟踪任何 Thread
实例,这些实例获取对 CompletableFuture
的引用完成它。
这是我认为你可以逃脱的执行类型的一个例子。
public static void main(String [] args)throws Exception {
ExecutorService service = Executors.newFixedThreadPool(1);
CompletableFuture< String> completable = new CompletableFuture<>();
未来<?> future = service.submit(new Runnable(){
@Override
public void run(){
for(int i = 0; i< 10; i ++){
if(Thread.interrupted()){
return; //保持未完成
}
尝试{
Thread.sleep(1000);
} catch(InterruptedException e ){
return; //仍然未完成
}
}
completable.complete(done);
}
});
Thread.sleep(2000);
//在两个
boolean cancel = future.cancel(true)中不是原子的;
if(cancelled)
completable.cancel(true); //如果执行已经完成,则可能没有被取消
if(completable.isCancelled()){
System.out.println(cancelled);
} else if(completable.isCompletedExceptionally()){
System.out.println(exception);
} else {
System.out.println(成功);
}
service.shutdown();
}
这假设正在执行的任务被设置为正确处理中断。
I know that CompletableFuture
design does not control its execution with interruptions, but I suppose some of you might have this problem. CompletableFuture
s are very good way to compose async execution, but given the case when you want the underlying execution to be interrupted or stopped when future is canceled, how do we do that? Or we must just accept that any canceled or manually completed CompletableFuture
will not impact the thread working out there to complete it?
That is, in my opinion, obviously a useless work that takes time of executor worker. I wonder what approach or design might help in this case?
UPDATE
Here is a simple test for this
public class SimpleTest {
@Test
public void testCompletableFuture() throws Exception {
CompletableFuture<Void> cf = CompletableFuture.runAsync(()->longOperation());
bearSleep(1);
//cf.cancel(true);
cf.complete(null);
System.out.println("it should die now already");
bearSleep(7);
}
public static void longOperation(){
System.out.println("started");
bearSleep(5);
System.out.println("completed");
}
private static void bearSleep(long seconds){
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
System.out.println("OMG!!! Interrupt!!!");
}
}
}
A CompletableFuture
is not related to the asynchronous action that may eventually complete it.
Since (unlike
FutureTask
) this class has no direct control over the computation that causes it to be completed, cancellation is treated as just another form of exceptional completion. Methodcancel
has the same effect ascompleteExceptionally(new CancellationException())
.
There may not even be a separate thread working on completing it (there may even be many threads working on it). Even if there is, there's no link from a CompletableFuture
to any thread that has a reference to it.
As such, there's nothing you can do through CompletableFuture
to interrupt any thread that may be running some task that will complete it. You'll have to write your own logic which tracks any Thread
instances which acquire a reference to the CompletableFuture
with the intention to complete it.
Here's an example of the type of execution I think you could get away with.
public static void main(String[] args) throws Exception {
ExecutorService service = Executors.newFixedThreadPool(1);
CompletableFuture<String> completable = new CompletableFuture<>();
Future<?> future = service.submit(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (Thread.interrupted()) {
return; // remains uncompleted
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return; // remains uncompleted
}
}
completable.complete("done");
}
});
Thread.sleep(2000);
// not atomic across the two
boolean cancelled = future.cancel(true);
if (cancelled)
completable.cancel(true); // may not have been cancelled if execution has already completed
if (completable.isCancelled()) {
System.out.println("cancelled");
} else if (completable.isCompletedExceptionally()) {
System.out.println("exception");
} else {
System.out.println("success");
}
service.shutdown();
}
This assumes that the task being executed is setup to handle interruptions correctly.
这篇关于如何中断CompletableFuture的底层执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!