为什么我的线程没有等待CompletableFutures完成`allOf()`?

时间:2017-03-21 14:25:18

标签: java multithreading java-8 completable-future

我正在Java 1.8中学习CompletableFuture并且无法理解allOf。似乎主线程不等待任何CompletableFuture完成。

有关我正在测试的示例,请参阅https://github.com/nurkiewicz/reactive/blob/master/src/test/java/be/more/reactive/S03_AllOf.java

测试作业在打印结果之前完成。

有两种(丑陋?)方法可以避免这种情况:1)在主线程上设置超时并等待两者完成。 2)在最后设置.get(),它将成为阻塞任务。

为什么会这样?

代码片段:

package be.more.reactive;

import be.more.reactive.util.BaseTest;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CompletableFuture;

public class S03_AllOf extends BaseTest {

    private static final Logger log = LoggerFactory.getLogger(S03_AllOf.class);

    private final CompletableFuture<String> futureResult1 = getFutureQueryResult("1"); //.exceptionally() ??
    private final CompletableFuture<String> futureResult2 = getFutureQueryResult("2");
    private final CompletableFuture<String> futureResult3 = getFutureQueryResult("3");
    private final CompletableFuture<String> futureResult4 = getFutureQueryResult("4");

    @Test
    public void allOf() throws Exception {
        final CompletableFuture<Void> futureResult = CompletableFuture.allOf(   //Void ?? I want List<String>
                futureResult1, futureResult2, futureResult3, futureResult4
        );

//        futureResult.thenAccept((Void vd) -> vd.??)   //no, it won't work

        futureResult.thenRun(() -> {
            try {
                log.debug("Query result 1: '{}'", futureResult1.get());
                log.debug("Query result 2: '{}'", futureResult2.get());
                log.debug("Query result 3: '{}'", futureResult3.get());
                log.debug("Query result 4: '{}'", futureResult4.get());   //a lot of manual work

                log.debug("Now do on complete");    //handling onComplete
            } catch (Exception e) {
                log.error("", e);
            }
        });

    }

}

在BaseTest中:

protected CompletableFuture<String> getFutureQueryResult(final String queryId) {
    return CompletableFuture.supplyAsync(
            () -> db.apply(new Query(queryId))

    );
}

在DB.java中

package be.more.reactive.db;

import java.util.concurrent.TimeUnit;

import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang3.RandomUtils.nextInt;
import static org.apache.commons.lang3.RandomUtils.nextLong;

public class DB {
    public String apply(Query query) {
        try {
            TimeUnit.SECONDS.sleep(nextLong(2, 4));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return String.format("%s_%s", randomAlphabetic(nextInt(4, 12)), query.getId());
    }
}

1 个答案:

答案 0 :(得分:1)

来自Javadoc

  

返回在所有给定的CompletableFutures完成时完成的新CompletableFuture。

Future是一个异步任务,在您调用get之前不会阻塞(只有在任务仍在运行时才会阻塞)。

在这种情况下,CompleteableFuture是所有Future的复合CompletableFuture。此未来仍将是阻止异步调用,您必须调用getjoin等待所有期货完成。再次,来自javadoc

  在继续执行程序之前

CompletableFutures,如:CompletableFuture.allOf(c1, c2, c3).join();

在我看来,你的(2)解决方案既不是丑陋也不是意想不到的功能。