我想了解的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