1

根据这个,下面的代码片段应该是异步的。

因此,输出应为:TP1、TP2、TP3、http ://openjdk.java.net/ 。

但是,当我运行它时,我得到:TP1、TP2、http ://openjdk.java.net/、TP3。

似乎“sendAsync”正在阻塞主线程。这不是我对 Async 方法的期望。

难道我做错了什么?

 public static void main(String[] args) {

    HttpClient client = HttpClient.newHttpClient();

    System.out.println("TP1");

    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("http://openjdk.java.net/"))
            .build();

    System.out.println("TP2");

    client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::uri)
            .thenAccept(System.out::println)
            .join();

    System.out.println("TP3");

}
4

1 回答 1

3

解释

你打电话join(),这将明确等待并阻止,直到未来完成。

CompletableFuture#join

完成时返回结果值,如果异常完成则抛出(未经检查的)异常。[...]

虽然没有明确提及,但从名字上看就很明显了(参考Thread#join中的“Waits for this thread to die.”),它只能等待调用完成才能返回结果。

该方法与CompletableFuture#get非常相似,它们在异常完成方面的行为不同:

如有必要,等待此未来完成,然后返回其结果。


解决方案

将未来放入一个变量中,然后在您真正想要等待它的时候加入。

例如:

System.out.println("TP2");

var task = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
        .thenApply(HttpResponse::uri)
        .thenAccept(System.out::println);

System.out.println("TP3");

task.join(); // wait later

或者永远不要等待它。HttpClient然后你的主线程可能会更早地死掉,但是只有在所有非守护线程都死掉并且用于异步任务的线程不是守护线程时,JVM才会关闭。


笔记

此外,永远不要依赖多线程执行的顺序。

即使您没有犯错,您观察到的顺序也是多线程执行的有效顺序

请记住,操作系统调度程序可以自由决定它执行的顺序 - 它可以是任何顺序。

于 2020-09-21T19:43:25.720 回答