Есть несколько решений, например, работа с асинхронными запросами . В этих случаях поток снова станет свободным, как только будут возвращены (и не обязательно завершены) CompletableFuture
, DeferredResult
, Callable
, ....
Например, допустим, мы настраиваем Tomcat следующим образом:
server.tomcat.max-threads=5 # Default = 200
И у нас есть следующий контроллер:
@GetMapping("/bar")
public CompletableFuture<String> getSlowBar() {
return CompletableFuture.supplyAsync(() -> {
silentSleep(10000L);
return "Bar";
});
}
@GetMapping("/baz")
public String getSlowBaz() {
logger.info("Baz");
silentSleep(10000L);
return "Baz";
}
Если бы мы запустили 100 запросов одновременно, вам пришлось бы подождать не менее 200 секунд, прежде чем будут обработаны все вызовы getSlowBar()
, поскольку только 5 могут обрабатываться в данный момент времени. С другой стороны, с асинхронным запросом вам придется подождать не менее 10 секунд, поскольку все запросы, скорее всего, будут обработаны одновременно, и тогда поток станет доступен для использования другими.
Есть ли разница между CompletableFuture
, Callable
и DeferredResult
? Нет никакой разницы в отношении результатов, они все ведут себя одинаково.
Способ обработки потоков несколько отличается:
- С
Callable
вы полагаетесь на то, что Spring выполнит Callable
с помощью TaskExecutor
- С
DeferredResult
вы должны обрабатывать нити самостоятельно. Например, выполняя логику в ForkJoinPool.commonPool()
.
- С
CompletableFuture
вы можете либо полагаться на пул потоков по умолчанию (ForkJoinPool.commonPool()
), либо указывать свой собственный пул потоков.
Кроме того, CompletableFuture
и Callable
являются частью спецификации Java, а DeferredResult
является частью среды Spring.
Имейте в виду, что хотя потоки освобождаются, соединения все еще остаются открытыми для клиента. Это означает, что при обоих подходах максимальное количество запросов, которые могут быть обработаны одновременно, ограничено 10000 и может быть настроено с помощью:
server.tomcat.max-connections=100 # Default = 10000