java线程在发出rest模板调用后,是否会在收到处于等待状态的响应后很快返回到运行状态?

zysjyyx4  于 2021-08-20  发布在  Java
关注(0)|答案(1)|浏览(336)

我有一个RESTAPI服务,它使用resttemplate为外部系统生成RESTAPI。超时设置为3秒。
为了进行这个外部调用,我创建了一个executor服务固定线程池。现在,在正常的测试中,一切正常,即使是内部调用设置的超时。但是当我在一个vm上使用jmeter对我的系统进行性能测试时,有4个内核,线程池大小固定为50,我开始观察以下内容。
在30 req/sec吞吐量之前,一切正常。
在45 req/sec吞吐量下,我观察到内部RESTAPI调用的延迟增加。虽然超时设置为3秒,但我观察到内部调用的延迟为5-8秒。

Instant startTime = Instant.now();
ResponseEntity<String> responseEntity = restTemplate
          .exchange(url, httpMethod, httpEntity, String.class);
Instant finishTime = Instant.now();
Log.info("Time diff is " + String.valueOf(Duration.between(startTime, finishTime).toMillis()));

在45 req/sec的吞吐量下,在单独线程中进行内部api调用时出现延迟,看起来系统正在等待线程在池中可用。
关于第二点,我想知道这是怎么可能的。我的一些理论是,
由于外部api调用是一个io操作,执行它的线程池线程进入“阻塞io完成”或等待状态,直到收到外部api的响应。当它收到响应时,线程进入“准备运行”状态,等待运行,由调度程序决定。现在,由于通信量已经很高,有很多其他线程已经处于“准备运行状态”&其中一些线程,即使在收到外部api响应后,也很晚才获得cpu时间,也就是计算finishtime的时候。这意味着,即使resttemplate调用在3秒内得到响应,执行log.info行也需要时间,因为时间差日志打印得很晚。
这个理论我认为是不对的,但我只是想表达我的想法。当线程进行rest api io调用并进入等待状态时,由于对池中线程的需求很高,线程是否可能从等待状态抢先以满足另一个请求?一旦从api调用接收到响应,就会分配另一个线程来接收该请求,分配另一个线程可能需要时间,从而导致延迟增加。
请让我知道我的第一个理论是否正确,或者如果不正确,在高吞吐量情况下会发生什么,这可能会导致外部api调用超过超时值延迟。

jckbn6z7

jckbn6z71#

理论1是正确的。
如果我们用更简单的术语来说,线程抢占是在内核级别而不是jvm级别完成的。一旦jvm将任务分配给线程,它就不能再控制它了。它是内核(取决于它的配置),如果高优先级线程需要cpu时间,它可以抢占正在运行的线程并将其置于等待状态。所以说jvm抢占等待下一个任务的线程的理论是不正确的。
基本上,配置特定大小的固定线程池的全部目的是对资源的使用施加一些限制。如果是像你在理论2中提到的那样,那么如果由于某种原因,每个线程开始进入无限等待状态,那么系统很快就会运行oom。

相关问题