如果手动完成,则不会调用 CompletableFuture 回调
CompletableFuture callback not called if completed manually
在这个 CompletableFuture 的基本示例中,我 运行 一个异步任务,当它完成时,应该触发一个异步回调。
我开始 运行 任务后一秒钟,在它完成之前,我完成了它。之后我再也看不到它 运行 异步回调了。
public static void main(String[] args) throws InterruptedException {
runTask();
Thread.sleep(1000);
completableFuture.complete("Test");
Thread.sleep(4000);
}
public static void runTask() {
completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("Running...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("...finished");
return "finished task";
})
.thenApplyAsync(s -> {
System.out.println("Apply on result: " + s);
return "Result: " + s;
})
}
结果是:
Running...
...finished
问题是,如果我添加另一个回调,那么它 运行 是第一个而不是第二个。
.thenApplyAsync(s -> {
System.out.println("Second apply with result: " + s);
return "Result: " + s;
})
则结果为:
Running...
...finished
Apply on result: finished task
阅读文档我了解到所有回调都会被调用,即使未来是手动完成的。我在这里遗漏了什么吗?
我想如果你写的稍微有点不同,应该是有道理的:
public static void runTask() {
CompletableFuture<String> one = CompletableFuture.supplyAsync(() -> {
System.out.println("Running...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("...finished");
return "finished task";
});
CompletableFuture<String> two = one.thenApplyAsync(s -> {
System.out.println("Apply on result: " + s);
return "Result: " + s;
});
completableFuture = two;
}
因此,one
在您的情况下启动得很好,但在 two
甚至可以启动之前,您发出 completableFuture.complete("Test");
。所以当 one
完成后,thenApplyAsync
就没有什么可做的了,因为那个已经完成了。
当你再增加一级时,基本上得到:
....
CompletableFuture<String> two = one.thenApplyAsync(s -> {
System.out.println("Apply on result: " + s);
return "Result: " + s;
});
CompletableFuture<String> three = two.thenApplyAsync(s -> {
System.out.println("Second apply with result: " + s);
return "Result: " + s;
});
completableFuture = three;
你大概可以看到这里发生了什么,甚至不需要我解释。
为此,我看不出文档在哪里明确说明了这一点。我想我们需要以某种方式在 package documentation 中看到它,通过:
When two or more threads attempt to complete, completeExceptionally, or cancel a CompletableFuture, only one of them succeeds.
这在某种程度上意味着,如果某个阶段尚未开始,但其他人,在外部 complete
s 它;那个阶段根本不会运行。这是有道理的,但包文档可能更清楚,imo。
在这个 CompletableFuture 的基本示例中,我 运行 一个异步任务,当它完成时,应该触发一个异步回调。
我开始 运行 任务后一秒钟,在它完成之前,我完成了它。之后我再也看不到它 运行 异步回调了。
public static void main(String[] args) throws InterruptedException {
runTask();
Thread.sleep(1000);
completableFuture.complete("Test");
Thread.sleep(4000);
}
public static void runTask() {
completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("Running...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("...finished");
return "finished task";
})
.thenApplyAsync(s -> {
System.out.println("Apply on result: " + s);
return "Result: " + s;
})
}
结果是:
Running...
...finished
问题是,如果我添加另一个回调,那么它 运行 是第一个而不是第二个。
.thenApplyAsync(s -> {
System.out.println("Second apply with result: " + s);
return "Result: " + s;
})
则结果为:
Running...
...finished
Apply on result: finished task
阅读文档我了解到所有回调都会被调用,即使未来是手动完成的。我在这里遗漏了什么吗?
我想如果你写的稍微有点不同,应该是有道理的:
public static void runTask() {
CompletableFuture<String> one = CompletableFuture.supplyAsync(() -> {
System.out.println("Running...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("...finished");
return "finished task";
});
CompletableFuture<String> two = one.thenApplyAsync(s -> {
System.out.println("Apply on result: " + s);
return "Result: " + s;
});
completableFuture = two;
}
因此,one
在您的情况下启动得很好,但在 two
甚至可以启动之前,您发出 completableFuture.complete("Test");
。所以当 one
完成后,thenApplyAsync
就没有什么可做的了,因为那个已经完成了。
当你再增加一级时,基本上得到:
....
CompletableFuture<String> two = one.thenApplyAsync(s -> {
System.out.println("Apply on result: " + s);
return "Result: " + s;
});
CompletableFuture<String> three = two.thenApplyAsync(s -> {
System.out.println("Second apply with result: " + s);
return "Result: " + s;
});
completableFuture = three;
你大概可以看到这里发生了什么,甚至不需要我解释。
为此,我看不出文档在哪里明确说明了这一点。我想我们需要以某种方式在 package documentation 中看到它,通过:
When two or more threads attempt to complete, completeExceptionally, or cancel a CompletableFuture, only one of them succeeds.
这在某种程度上意味着,如果某个阶段尚未开始,但其他人,在外部 complete
s 它;那个阶段根本不会运行。这是有道理的,但包文档可能更清楚,imo。