我认为新的java 8 CompletableFuture能够使用“thenComposeAsync”方法一个接一个地执行异步任务而不会阻塞线程。
我认为情况并非如此。线程同步等待任务完成(CompletableFuture.java:616 r = fr.waitingGet(false);)
如果nThreads< = 2:
,下面的代码永远不会执行“任务3”int nThreads= 2;
Executor e= Executors.newFixedThreadPool(nThreads);
CompletableFuture.runAsync( () -> {
System.out.println("task 1 threadId " + Thread.currentThread().getId());
}, e).thenComposeAsync( (Void v1) -> {
return CompletableFuture.runAsync( () -> {
System.out.println("task 2 threadId " + Thread.currentThread().getId());
}, e).thenComposeAsync((Void v2) -> {
return CompletableFuture.runAsync( () -> {
System.out.println("task 3 threadId " + Thread.currentThread().getId());
}, e);
}, e);
}, e).join();
System.out.println("finished");
¿我应该使用哪些其他java库?我希望代码在一个线程中执行(nThreads = 1)。
答案 0 :(得分:0)
这个工作正常。我打电话给:
,而不是CompletableFuture.thenComposeAsyncstatic public <T,U> CompletableFuture<U> thenComposeAsyncNoWait(CompletableFuture<T> first, Function<? super T, ? extends CompletableFuture<U>> fn, Executor executor) {
CompletableFuture<U> ret= new CompletableFuture<>();
first.handleAsync( (T t, Throwable e) -> {
if ( e != null )
ret.completeExceptionally(e);
else
fn.apply(t).handleAsync( (U u, Throwable e2) -> {
if ( e2 != null )
ret.completeExceptionally(e2);
else
ret.complete(u);
return null;
}, executor);
return null;
}, executor);
return ret;
}
答案 1 :(得分:0)
使用thenApply似乎可以正常工作
int nThreads= 1;
ExecutorService e= Executors.newFixedThreadPool(nThreads);
System.out.println("starting");
CompletableFuture<Integer> compFuture = CompletableFuture.supplyAsync( () -> {
System.out.println("task "+42+" threadId " + Thread.currentThread().getName());
return 42;
}, e).thenApplyAsync(i -> {
System.out.println("task "+i+" threadId " + Thread.currentThread().getName());
return i+1;
}, e).thenApplyAsync(i -> {
System.out.println("task "+i+" threadId " + Thread.currentThread().getName());
return i+1;
}, e);
compFuture.join();
e.shutdown();
e.awaitTermination(1000, TimeUnit.SECONDS);
System.out.println("finished");
答案 2 :(得分:0)
如果您使用thenComposeAsync
代替ForkJoinPool
,则您的示例可以与ExecutorService
一起使用:
final ExecutorService e = new ForkJoinPool(nThreads);
另外,请务必在最后关闭服务(否则程序不会退出):
e.shutdown();
编辑:或许还有一些解释:
如果你绘制包含由thenComposeAsync
引起的任务的依赖图,它必须在它们的后继者可以运行之前完成(因为它们提供传递给它们的后继者的返回值),你会发现你需要两个以上使用对手调度程序执行图形的线程。
通常,很难预测执行动态创建的任务图所需的最小线程数。 ForkJoinPool
承认通过尝试保持在给定的并行度级别内,但在需要时创建其他线程。