java库,它可以异步编写future(flatMap)

时间:2014-04-14 13:17:20

标签: java java-8 future

我认为新的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)。

3 个答案:

答案 0 :(得分:0)

这个工作正常。我打电话给:

,而不是CompletableFuture.thenComposeAsync
static 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承认通过尝试保持在给定的并行度级别内,但在需要时创建其他线程。