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

Java异步HttpClient请求似乎阻止了主线程?,java,multithreading,asynchronous,java-http-client,Java,Multithreading,Asynchronous,Java Http Client,根据下面的说明,代码段应该是异步的 因此,输出应为:TP1、TP2、TP3、 然而,当我运行它时,我得到了:TP1,TP2,TP3 似乎“sendAsync”正在阻塞主线程。这不是我对异步方法的期望 我做错什么了吗 public static void main(String[] args) { HttpClient client = HttpClient.newHttpClient(); System.out.println("TP1");

根据下面的说明,代码段应该是异步的

因此,输出应为:TP1、TP2、TP3、

然而,当我运行它时,我得到了:TP1,TP2,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()
,这将显式地等待并阻止,直到将来完成

发件人:

完成时返回结果值,如果异常完成,则抛出(未选中)异常。[……]

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

该方法非常类似于,它们在异常完成方面的行为不同:

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


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

例如:

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


笔记 另外,永远不要依赖多线程执行的顺序

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

请记住,操作系统调度程序可以自由决定执行什么命令的顺序—可以是任何顺序。

解释 您调用
join()
,这将显式地等待并阻止,直到将来完成

发件人:

完成时返回结果值,如果异常完成,则抛出(未选中)异常。[……]

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

该方法非常类似于,它们在异常完成方面的行为不同:

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


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

例如:

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


笔记 另外,永远不要依赖多线程执行的顺序

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


请记住,OS调度器可以自由决定执行什么的顺序—可以是任何顺序。

是否有方法在收到头和正文时触发事件。我希望能够获取URL数据,并在数据准备就绪时中断主线程。类似于JavaScript中的XMLHttpRequest对象。回答得很好,非常感谢。当然,你可以在未来的基础上编写任务。您已经在使用
然后应用
然后接受
执行此操作。您可以在将来的基础上编写任意多的内容。如果您希望在收到响应头时执行某些操作,您可以提供自己的
BodyHandler
,它可能只是内置
BodyHandler
的薄薄包装。不过,请确保不要在
BodyHandler
回调中执行任何阻塞操作,因为这可能会阻塞
HttpClient
线程,并可能阻塞整个响应处理。是否有方法在接收到头和主体时触发事件。我希望能够获取URL数据,并在数据准备就绪时中断主线程。类似于JavaScript中的XMLHttpRequest对象。回答得很好,非常感谢。当然,你可以在未来的基础上编写任务。您已经在使用
然后应用
然后接受
执行此操作。您可以在将来的基础上编写任意多的内容。如果您希望在收到响应头时执行某些操作,您可以提供自己的
BodyHandler
,它可能只是内置
BodyHandler
的薄薄包装。不过,请确保不要在
BodyHandler
回调中执行任何阻塞操作,因为这可能会阻塞
HttpClient
线程,并可能阻塞整个响应处理。