问题描述
因此,输出应为: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()
,它将明确等待并阻止,直到将来完成。
完成后返回结果值,如果异常完成则抛出(未经检查的)异常。 [...]
尽管没有明确提及,但从名称上可以明显看出(请参阅Thread#join,其中“等待该线程死亡。” ),它只能通过等待调用来返回结果。完成。
该方法与CompletableFuture#get非常相似,它们在异常完成方面的行为有所不同:
等待将来完成,然后返回结果。
解决方案
将future放入变量中,然后在您真正想要等待时加入。
例如:
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才会关闭。
注意
此外,永远不要依赖多线程执行的顺序。
即使您不会犯错,您观察到的顺序也将是多线程执行的有效顺序。
请记住,操作系统调度程序可以自由决定执行命令的顺序-可以是任何顺序。