Java异步HttpClient请求似乎阻塞了主线程?

huangapple go评论84阅读模式
英文:

Java Async HttpClient request seems to block the main thread?

问题

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

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

然而,当我运行代码时,得到的却是:TP1,TP2,http://openjdk.java.net/,TP3。

看起来 "sendAsync" 方法阻塞了主线程。这不是我从一个异步方法中期望的行为。

我是否做错了什么?

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");
}
英文:

According to this the following snippet should be Async.

Therefore, the output should read: TP1, TP2, TP3, http://openjdk.java.net/.

However, when I run it I get: TP1, TP2, http://openjdk.java.net/, TP3.

It seems "sendAsync" is blocking the main thread. This is not what I expected from an Async method.

Am I doing something wrong?

 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");

}

答案1

得分: 3

Explanation

您调用join(),这会显式地等待并阻塞,直到未来完成为止。

CompletableFuture#join

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

虽然没有明确提到,但从名称中可以明显看出(参见Thread#join,它“等待此线程死亡。”),它只能通过等待调用完成来返回结果。

该方法与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(); // 稍后等待

或者根本不要在其上等待。那么您的主线程可能会更早地终止,但是只有在所有非守护线程都死亡并且HttpClient用于异步任务的线程不是守护线程时,JVM 才会关闭。


注意

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

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

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

英文:

Explanation

You call join() and that will explicitly wait and block until the future is completed.

From CompletableFuture#join:

> Returns the result value when complete, or throws an (unchecked) exception if completed exceptionally. [...]

Although not explicitly mentioned but obvious from the name (refer to Thread#join which "Waits for this thread to die."), it can only return a result by waiting for the call to complete.

The method is very similar to CompletableFuture#get, they differ in their behavior regarding exceptional completion:

> Waits if necessary for this future to complete, and then returns its result.


Solution

Put the future into a variable and join later, when you actually want to wait for it.

For example:

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

Or never wait on it. Then your main-thread might die earlier but the JVM only shuts down once all non-daemon threads are dead and the thread used by HttpClient for the async task is not a daemon thread.


Note

Also, never rely on the order of multithreaded execution.

Even if you wouldnt have made a mistake, the order you observe would be a valid order of a multithreaded execution.

Remember that the OS scheduler is free to decide in which order it executes what - it can be any order.

huangapple
  • 本文由 发表于 2020年9月22日 03:37:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/63998918.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定