🛠️ ThreadPoolExecutor saturated, а CPU ещё не 100%?
Это возможно: threads могут ждать database, HTTP, filesystem, locks или другой blocking dependency.
Для execute() логика такая:
threads < corePoolSize → новый thread core достигнут → сначала queue queue не принимает → threads растут до maximumPoolSize queue не принимает + pool at max → RejectedExecutionHandler
Отсюда важная ловушка.
corePoolSize = 10 maximumPoolSize = 100 queue = new LinkedBlockingQueue<>()
Без заданной capacity такая queue практически неограниченная.
После загрузки core threads задачи будут накапливаться в queue, а pool обычно не вырастет до 100.
Поэтому увеличение maximumPoolSize может ничего не изменить.
С bounded queue executor после её заполнения может расти выше core — до max.
Но bounded queue сама по себе overload не решает: нужна понятная rejection/backpressure strategy.
RejectedExecutionException тоже не обязательна.
Её бросает AbortPolicy; другая policy может вести себя иначе.
Перед tuning соберите:
— core/max pool size; — poolSize и approximate activeCount; — тип и capacity queue; — incoming и completed rate; — task latency; — rejection policy; — downstream latency.
Главный вопрос:
это временный burst или incoming rate стабильно выше completion rate?
Во втором случае большая queue только откладывает проблему.
Сохраните параметры, которые нужно собрать до изменения размера thread pool.