我想了解的Java异步的好处。爪哇 - 异步 - 线程池
方案1: 我有部署到Tomcat的弹簧引导web应用程序,使用Tomcat min和max线程都设定在200
@Service
public class MyService{
public String execute(){
try {
//simulate blocking
Thread.sleep(3000);
} catch (InterruptedException e) {}
return "OK";
}
}
@RestController
public class MyController {
@Autowired
private MyService service;
@RequestMapping("/test")
public String test(){
return service.execute();
}
}
方案2:我有部署到Tomcat的弹簧引导web应用程序与Tomcat的最小和最大线程均设定为100
@Service
public class MyService{
public String execute(){
try {
//simulate blocking
Thread.sleep(3000);
} catch (InterruptedException e) {}
return "OK";
}
}
@RestController
public class MyController {
@Autowired
private MyService service;
private ExecutorService executorService = Executors.newFixedThreadPool(100);
@RequestMapping("/test")
public DeferredResult<String> test(){
DeferredResult<String> deferredResult = new DeferredResult<>();
CompletableFuture.supplyAsync(service::execute, executorService).
whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));
return deferredResult;
}
}
在每个场景中,线程的总数为200
但我不明白如何风光ario 2会有更好的表现:
在场景1中,如果有400个请求同时进入,前200个将由200个http线程提供服务,接下来的200个将等待3秒(再加上一点),直到其中一个线程再次可用。
所以可以通过为每6秒400个请求=每秒66.6请求。
的平均响应时间是(200 * 3 + 200 * 6)/(400)=4.5秒
在方案2中,如果 400个请求在同一时间进入。前100个将由100个http线程立即提供服务,这些线程中的每一个都会调用该服务,而不是等待结果,然后立即恢复,并可用于接下来的100个请求。 但现在用于第二100个请求,当每个HTTP线程调用服务,该服务目前等待3秒(减去一个位)来完成处理前100个线程。所以下一个100队列(在executorservice的线程池中)。 因此,几乎没有任何时间,我们处理了所有400个请求,但 100正在服务中处理(等待3秒钟),而300个正在执行程序服务线程池中排队。 3秒后,前100个完成,接下来100个出队并处理,等等。
所以吞吐量是在12秒内400个请求=每秒
的平均响应时间是 (100 * 3 + 100 * 6 + 100 * 9 + 100 * 12)/(400)= 7.5 33.3请求秒
现在,有人可能会说'我可以通过增加执行程序服务线程池中的线程数来改进方案2',我可以回复'好的,然后我可以增加tomcat中的线程数在场景1中的池数量相同'
感谢您的回复。 但是,如果服务也是异步并立即返回,哪个线程正在等待完成可完成未来的响应 –
API的调用者仍在等待“OK”响应。有些线程必须返回该响应,即使它不是tomcat http线程。 –
@ jonathan.stiles - 当计时器任务的时间耗尽时,任务被分配给线程池上的空闲线程,或者如果没有空闲线程,则将其分配给下一个线程中服务的队列游泳池变得闲置。线程池中的这个线程最终完成DeferredResult并将响应发送给客户端。在适当的异步中,所有线程都要么完成工作,要么在等待调度的线程池中处于空闲状态。 – antlersoft