Java Async HttpClient 请求似乎阻塞了主线程?
Java Async HttpClient request seems to block the main thread?
根据 this,以下代码段应该是异步的。
因此,输出应为: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");
}
说明
您调用 join()
,它将明确等待并阻塞,直到未来完成。
Returns the result value when complete, or throws an (unchecked) exception if completed exceptionally. [...]
虽然没有明确提到但是从名字上就可以看出(参考Thread#join其中“等待这个线程死亡”),它只能return等待调用完成的结果。
该方法与CompletableFuture#get非常相似,它们在异常完成方面的行为不同:
Waits if necessary for this future to complete, and then returns its result.
解决方案
将未来放入一个变量中,稍后加入,当你真正想要等待它时。
例如:
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
或者从不等待它。那么你的 main-thread 可能会更早死掉,但 JVM 只会在所有 non-daemon 线程都死掉并且 HttpClient
用于异步任务的线程不是守护线程后才会关闭。
备注
此外,永远不要依赖多线程执行的顺序。
即使您没有犯错,您观察到的顺序也是多线程执行的有效顺序。
请记住,OS 调度程序可以自由决定它执行什么的顺序 - 它可以是任何顺序。
根据 this,以下代码段应该是异步的。
因此,输出应为: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");
}
说明
您调用 join()
,它将明确等待并阻塞,直到未来完成。
Returns the result value when complete, or throws an (unchecked) exception if completed exceptionally. [...]
虽然没有明确提到但是从名字上就可以看出(参考Thread#join其中“等待这个线程死亡”),它只能return等待调用完成的结果。
该方法与CompletableFuture#get非常相似,它们在异常完成方面的行为不同:
Waits if necessary for this future to complete, and then returns its result.
解决方案
将未来放入一个变量中,稍后加入,当你真正想要等待它时。
例如:
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
或者从不等待它。那么你的 main-thread 可能会更早死掉,但 JVM 只会在所有 non-daemon 线程都死掉并且 HttpClient
用于异步任务的线程不是守护线程后才会关闭。
备注
此外,永远不要依赖多线程执行的顺序。
即使您没有犯错,您观察到的顺序也是多线程执行的有效顺序。
请记住,OS 调度程序可以自由决定它执行什么的顺序 - 它可以是任何顺序。