Пытаюсь сделать экзекутор с динамическим размером core нитей. С бустом, на старте работы экзекутора и последующим снижением кол-ва core нитей. Дано: некоторое кол-во объектов менеджеров, которые работают с объектами Rou, сейчас менеджеров 6, будет больше, кол-во объектов Rou не известно заранее. Есть отдельная нить Producer которая кладёт в экзекутор задачи, по одной для каждого объекта Rou, примерно раз в минуту (один тик = 55 сек). То есть Producer для всех Rou положила в экзекутор задачи, сделала описаный ниже код и заснула на 55 сек, это один тик. Задача для объекта Rou, это найти свой менеджер из 6ти и запомнить, его чтоб в следующий раз не искать, а работать с уже известным и сделать через найденый менеджер вычисление, пару секунд. Rou друг с другом не связаны, вычисление может делать любая нить в экзекуторе. По скольку Rou, своего менеджера при первом проходе (тике) Producer с задачами для Rou, надо ещё найти, а это может занять до 12 сек ( эти же 12 сек таймаут для убийства нити в экзекуторе) , я экзекутор создаю сначала с corePoolSize = maximumPoolSize = кол-во объектов Rou и верхним потолком в 32. , а очередь для задач в экзекуторе в двое больше чем кол-во объектов Rou . вот так
corePoolSize = maximumPoolSize = Math.max(1, Math.min(mCheckedSims.size(), 32)); // в начале и core и max нитей одинаково, максимально возможное для буста при поиске менеджеров
executorPoolQueueSize = Math.max(1, mCheckedSims.size() * 2); // очередь х2

routersExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 12, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(executorPoolQueueSize), lowPriorityFactory);
            routersExecutor.allowCoreThreadTimeOut(true); // сразу разрешаю core нитям умирать, что они сделают после буста (первой выполненой задачи)
в конце каждого тика (55 сек) Produce, после отправления в экзекутор задач всем Rou, я пытаюсь занизить corePoolSize, до нормальных значений, 1 нить на 25 Rou
if (corePoolSize == maximumPoolSize) { // после первого же тика Producer, буст (отправка первых задач для Rou)  закончен,
// значение для corePoolSize занизится
   corePoolSize = Math.min(Math.max(1, (mCheckedSims.size() + 24) / 25), maximumPoolSize); // да тут corePoolSize может остаться таким же если
// mCheckedSims.size() (это кол-во Rou) будет в тысячах, но в этом случае код будет работать без заужения, на все 32 нити
}

if (executor.getCorePoolSize() == maximumPoolSize && corePoolSize < maximumPoolSize) { // значит это второй тик и corePoolSize занижен
                executor.setCorePoolSize(corePoolSize);  // применяем зауженый corePoolSize
            }
и тут же, в конце каждого тика Producer пытаюсь запретить corePool нитям умирать, вот с такой проверкой, ожидая что запрет сработает на одном из следующих, после первого, тиках. Чтоб в экзекуторе после буста жили адекватное кол-во нитей, 1 к 25.
ThreadPoolExecutor executor = routersExecutor;
        if (executor != null
                && corePoolSize < maximumPoolSize // если значение  corePoolSize был уменьшено ( и задано) после буста на старте
                 && !executor.getQueue().isEmpty() // если очередь задач не пуста при зауженном corePoolSize, значит стартовые лишние core нити для буста будут (или уже) убиты по таймауту 12 сек после выполения всех задач в очереди, так как очередь x2 от кол-во задач и заполняется за 2 тика 110 сек или задач слишком много и все нити пашут
                 && executor.getActiveCount() <= corePoolSize // если работающих нитей меньше или  равно зауженного corePoolSize при не пустой очереди, значит стартовые  доп. нити точно убиты и задачи кладутся в очередь.
                 && executor.allowsCoreThreadTimeOut()) { // corePool нитям всё ещё разрешено умирать (чтоб умирали стартовые доп. нити)
            executor.allowCoreThreadTimeOut(false); // запрещаю заниженому кол-ву  corePoolSize нитей умирать, раз буст закончен и чтоб corePool не схлопывался до 0, а в экзекуторе жили нормальное кол-во нитей.
        }
весь указанный код выполняет одна нить Producer хочется второе мнение по логике проверок перед executor.allowCoreThreadTimeOut(false); и вообще его использование после того как экзекутор начал работу, а то gemini что то перестал открываться, я жду что у меня на старте будет в экзекутере кол-во нитей равно кол-ву Rou или 32 максимум, при первой же выполненой задаче каждому Rou найдётся менеджер, после чего corePool я занижу до адекватных размеров, 1 нить на 25 Rou, и далее. при необходимости, даже если менеджеры для каких то Rou не найдутся, доп нити смогут появлятся и умирать по таймауту 12 сек. он выбран с учётом логики приложения, в принципе всё работало при создании пула с corePoolSize = 1 на старте, всё работало хорошо. но захотелось ускорить старт, так как всего одна нить на старте и двойная очередь, на 3 минуты откладывали появление доп нитей для поиcка менеджеров большому кол-ву Rou, которое изначально не известно :). То есть я хочу имень быстрый старт, потом чистка от лишних нитей, но так чтоб при простое оставалось в экзекуторе адекватное кол-во нитей, а не 0 из за executor.allowCoreThreadTimeOut(true); при создании экзекутора.