Java 为什么';这个线程池不能同时执行HTTP请求吗?

Java 为什么';这个线程池不能同时执行HTTP请求吗?,java,http,threadpool,executorservice,resttemplate,Java,Http,Threadpool,Executorservice,Resttemplate,我编写了几行代码,将向运行在我机器上的服务发送50个HTTP GET请求。该服务将始终sleep 1秒,并返回一个HTTP状态代码200和一个空正文。正如预期的那样,代码运行大约50秒 为了加快速度,我尝试创建一个带有4个线程的ExecutorService,这样我就可以同时向我的服务发送4个请求。我希望代码运行大约13秒 final List url=new ArrayList(); 对于(int i=0;i(可调用)(->{ System.out.println(LocalDateTime.

我编写了几行代码,将向运行在我机器上的服务发送50个HTTP GET请求。该服务将始终
sleep 1
秒,并返回一个HTTP状态代码200和一个空正文。正如预期的那样,代码运行大约50秒

为了加快速度,我尝试创建一个带有4个线程的
ExecutorService
,这样我就可以同时向我的服务发送4个请求。我希望代码运行大约13秒

final List url=new ArrayList();
对于(int i=0;i<50;i++)
URL.add(“http://localhost:5000/test/“+i);
最终RestTemplate RestTemplate=新RestTemplate();
最终列表任务=URL
.stream()
.map(u->(可调用)(->{
System.out.println(LocalDateTime.now()+“-”+线程.currentThread().getName()+”:“+u);
返回restemplate.getForObject(u,String.class);
}).collect(Collectors.toList());
final ExecutorService ExecutorService=Executors.newFixedThreadPool(4);
最终长启动=System.currentTimeMillis();
试一试{
最终列表期货=executorService.invokeAll(任务);
最终列表结果=futures.stream().map(f->{
试一试{
返回f.get();
}捕获(中断异常|执行异常e){
抛出新的非法状态异常(e);
}
}).collect(Collectors.toList());
系统输出打印项次(结果);
}最后{
executorService.shutdown();
执行器服务。等待终止(10,时间单位。秒);
}
最终长时间运行=System.currentTimeMillis()-开始;
System.out.println(“take”+appeased+“ms…”);
但是-如果您查看调试输出的秒数-看起来前4个请求是同时执行的,但所有其他请求都是一个接一个地执行的:

2018-10-21T17:42:16.160-pool-1-thread-3:http://localhost:5000/test/2
2018-10-21T17:42:16.160-pool-1-thread-1:http://localhost:5000/test/0
2018-10-21T17:42:16.160-pool-1-thread-2:http://localhost:5000/test/1
2018-10-21T17:42:16.159-pool-1-thread-4:http://localhost:5000/test/3
2018-10-21T17:42:17.233-pool-1-thread-3:http://localhost:5000/test/4
2018-10-21T17:42:18.232-pool-1-thread-2:http://localhost:5000/test/5
2018-10-21T17:42:19.237-pool-1-thread-4:http://localhost:5000/test/6
2018-10-21T17:42:20.241-pool-1-thread-1:http://localhost:5000/test/7
...
花了50310毫秒。。。
因此,出于调试目的,我将HTTP请求更改为
sleep
调用:

//返回restemplate.getForObject(u,String.class);
时间单位。秒。睡眠(1);
返回“”;
现在代码按预期工作:

...
Took 13068 ms...

所以我的问题是,为什么带有睡眠调用的代码能像预期的那样工作,而带有HTTP请求的代码却不能?我怎样才能让它以我预期的方式运行呢?

从信息中,我可以看出这是最可能的根本原因:

您发出的请求是并行执行的,但是满足这些请求的HTTP服务器每次处理一个请求

因此,当您开始发出请求时,
executor服务将同时触发请求,因此您将同时获得前4个请求

但是HTTP服务器可以一次一个响应请求,即每次1秒后

现在,当第一个请求得到满足时,executor服务会选择另一个请求并激发它,这将一直持续到最后一个请求

一次在HTTP服务器上阻止4个请求,这些请求被一个接一个地连续提供


要获得该理论的
概念证明
,您可以使用消息传递服务(队列),该服务可以同时从4个通道接收测试。这将减少时间。

从信息中,我可以看出这是最可能的根本原因:

您发出的请求是并行执行的,但是满足这些请求的HTTP服务器每次处理一个请求

因此,当您开始发出请求时,
executor服务将同时触发请求,因此您将同时获得前4个请求

但是HTTP服务器可以一次一个响应请求,即每次1秒后

现在,当第一个请求得到满足时,executor服务会选择另一个请求并激发它,这将一直持续到最后一个请求

一次在HTTP服务器上阻止4个请求,这些请求被一个接一个地连续提供


要获得该理论的
概念证明
,您可以使用消息传递服务(队列),该服务可以同时从4个通道接收测试。这应该会减少时间。

可能是因为前四个线程很忙,所以之后就没有并行性了。“睡眠(1)”基本上没有时间,所以它马上就结束了。您的处理显然比“sleep(1)”要长得多。@markspace没有额外的处理,sleep(1)实际上是指第二个:
plackup-e'sub{sleep 1;return[200,[“Content Type”=>“text/plain”],[“”]}
另一端有多少线程?我猜问题是服务器逻辑(您的业务服务). 看起来您的服务器不能同时提供多个请求。你能把你的服务器代码放进去吗?可能是因为前四个线程都很忙,所以之后就没有并行性了。“睡眠(1)”基本上没有时间,所以它马上就结束了。您的处理显然比“sleep(1)”要长得多。@markspace没有额外的处理,sleep(1)实际上是指第二个:
plackup-e'sub{sleep 1;return[200,[“Content Type”=>“text/plain”],[“”]}
另一端有多少线程?我猜问题是服务器逻辑(您的业务服务). 看起来你的服务器没有