Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 11 HTTP客户端异步执行_Java_Http_Asynchronous_Completable Future_Java 11 - Fatal编程技术网

Java 11 HTTP客户端异步执行

Java 11 HTTP客户端异步执行,java,http,asynchronous,completable-future,java-11,Java,Http,Asynchronous,Completable Future,Java 11,我正在尝试来自JDK 11的新HTTP客户端API,特别是它执行请求的异步方式。但有一点我不确定自己是否理解(某种程度上是实现方面)。在报告中,它说: 返回的CompletableFuture实例的异步任务和依赖操作在客户机的执行器提供的线程上执行(如果可行) 据我所知,这意味着如果我在创建HttpClient对象时设置了自定义执行器: ExecutorService executor = Executors.newFixedThreadPool(3); HttpClient httpClie

我正在尝试来自JDK 11的新HTTP客户端API,特别是它执行请求的异步方式。但有一点我不确定自己是否理解(某种程度上是实现方面)。在报告中,它说:

返回的
CompletableFuture
实例的异步任务和依赖操作在客户机的
执行器提供的线程上执行(如果可行)

据我所知,这意味着如果我在创建
HttpClient
对象时设置了自定义执行器:

ExecutorService executor = Executors.newFixedThreadPool(3);

HttpClient httpClient = HttpClient.newBuilder()
                      .executor(executor)  // custom executor
                      .build();
然后,如果异步发送请求并在返回的
CompletableFuture
上添加依赖操作,则依赖操作应在指定的执行器上执行

httpClient.sendAsync(request, BodyHandlers.ofString())
          .thenAccept(response -> {
      System.out.println("Thread is: " + Thread.currentThread().getName());
      // do something when the response is received
});
但是,在上面的依赖操作中(consumer在
然后accept
),我看到执行它的线程来自公共池,而不是自定义执行器,因为它打印的
线程是:ForkJoinPool.commonPool-worker-5

这是实现中的一个bug吗?还是我错过了什么?我注意到它说“实例是在客户机的执行器提供的线程上执行的,,如果可行的话,”,那么这是不适用的情况吗


请注意,我也尝试了验收同步,结果也是一样的。

简短版本:我认为您已经确定了一个实现细节,“在实际情况下”意味着无法保证将使用提供的执行器

详细内容:

我已经从下载了JDK 11源代码。(
jdk11-f729ca27cf9a
撰写本文时)

src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java
中,有以下类:

/**
 * A DelegatingExecutor is an executor that delegates tasks to
 * a wrapped executor when it detects that the current thread
 * is the SelectorManager thread. If the current thread is not
 * the selector manager thread the given task is executed inline.
 */
final static class DelegatingExecutor implements Executor {
如果
IsInSelectThread
为true,则此类使用
executor
,否则任务将以内联方式执行。这归结为:

boolean isSelectorThread() {
    return Thread.currentThread() == selmgr;
}
其中,
selmgr
是一个
选择器管理器
Edit:此类也包含在
HttpClientImpl.java
中:

// Main loop for this client's selector
private final static class SelectorManager extends Thread {
结果:我猜测,在实际情况下,这意味着它依赖于实现,并且不能保证所提供的
执行器将被使用

注意:这与默认执行器不同,在默认执行器中,生成器不提供
执行器。在这种情况下,代码显然会创建一个新的缓存线程池。换句话说,如果构建器提供了一个
执行器
,则会对
SelectorManager
进行身份检查。

我刚刚找到一个更新的(我最初链接到的那一个看起来很旧),它解释了这个实现行为:

通常,异步任务要么在调用操作的线程(例如HTTP请求)中执行,要么由客户端服务器提供的线程执行相关任务,由返回的CompletionStages或CompletableFutures触发的任务,这些任务没有明确指定执行者,执行方式与
CompletableFuture
相同,如果操作在注册相关任务之前完成,则执行方式与调用线程相同

CompletableFuture
的默认执行器是公共池

我还发现了引入这种行为的方法,API开发人员在其中充分解释了这一点:

2) 依赖任务在公共池中运行 依赖任务的默认执行已更新为与CompletableFuture的默认执行器在同一执行器中运行。这对于已经使用CF的开发人员来说更为熟悉,并且降低了HTTP客户机执行其任务时线程不足的可能性。这只是默认行为,如果需要,HTTP客户端和CompletableFuture都允许更精细的控制


抱歉,如果这很愚蠢,请帮助我理解,您是如何解释它来自公共池而不是自定义执行器的,因为它打印的线程是:ForkJoinPool.commonPool-worker-5?…我还尝试了
System.out.println(httpClient.executor().get().equals(executor))
然后accept
消费者中,它打印
true
@nullpointer,我假设他打印出
线程.currentThread().getName()
中,然后接受
使用者
,该名称表示
线程
来自公共
ForkJoinPool
而非自定义
执行器
。换句话说,OP并不是说
HttpClient
Executor
已经更改,OP想知道为什么依赖
CompletableFuture
阶段使用不同的线程池执行。@nullpointer正是Slaw所说的。我还知道线程来自公共池,因为我可以为自定义执行器创建的线程指定特殊名称,以清楚地标识它们。对于
httpClient.executor()
,此方法只返回我在创建时指定的executor,这不是
thenAccept
所使用的。@Slaw@manouti谢谢。我得到了你们两位所指的,确实尝试了向执行器提供一个自定义命名线程,并且可以看到它没有在
然后accept
中使用。将进一步查找有关其实际部分以及bug数据库的详细信息。结果表明,在这个API的开发过程中,文档已经更新,因此它描述了这种行为。最新的文档链接感谢您的回答。这似乎确实是一个实施细节。但是,关于最后一点,当我没有在客户端设置中指定执行器时,依赖操作仍然使用公共池,而不是幕后的默认线程缓存执行器。“这只是默认行为,HTTP客户端和CompletableFuture都允许更精细的控制,如果需要的话。”对于
CompletableFuture
,我假设他的意思是使用
*Async(…,Executor)
方法变量。然而