Страницы

Поиск по вопросам

четверг, 7 марта 2019 г.

Почему всегда threadPoolExecutor.getActiveCount() <= maximumPoolSize/2?

Есть очередь задач, создана следующим образом:
LinkedBlockingQueue queue = new LinkedBlockingQueue(); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(maximumPoolSize, maximumPoolSize, 50000L, TimeUnit.MILLISECONDS, queue);
Значение maximumPoolSize равно 200. Во время работы в queue попадает большое количество потоков (больше тысячи), но значение, возвращаемое методом threadPoolExecutor.getActiveCount() всегда меньше либо равно 100. Например, значения threadPoolExecutor.getActiveCount() и queue.size() логируются следующим образом:
logger.debug("Активные потоки: " + threadPoolExecutor.getActiveCount() + ". В очереди " + queue.size() + " потоков.");
и в итоге мы получаем следующую картину:
Активные потоки: 1. В очереди 0 потоков. Активные потоки: 2. В очереди 0 потоков. Активные потоки: 3. В очереди 0 потоков. Активные потоки: 4. В очереди 0 потоков. Активные потоки: 5. В очереди 0 потоков. ... Активные потоки: 86. В очереди 0 потоков. Активные потоки: 87. В очереди 1 потоков. Активные потоки: 88. В очереди 1 потоков. Активные потоки: 89. В очереди 1 потоков. Активные потоки: 90. В очереди 1 потоков. ... Активные потоки: 99. В очереди 1 потоков. Активные потоки: 100. В очереди 1 потоков. Активные потоки: 100. В очереди 2 потоков. Активные потоки: 100. В очереди 3 потоков. Активные потоки: 100. В очереди 4 потоков. ... Активные потоки: 100. В очереди 1874 потоков. Активные потоки: 100. В очереди 1875 потоков. Активные потоки: 100. В очереди 1876 потоков. Активные потоки: 100. В очереди 1877 потоков. Активные потоки: 100. В очереди 1878 потоков. Активные потоки: 100. В очереди 1879 потоков. Активные потоки: 100. В очереди 1880 потоков. Активные потоки: 100. В очереди 1881 потоков. Активные потоки: 100. В очереди 1882 потоков. Активные потоки: 100. В очереди 1883 потоков.
В документации написано, что метод threadPoolExecutor.getActiveCount() возвращает приблизительное количество потоков с активно выполняющимися задачами. Но почему максимальный порог этого приблизительного значения тут равен maximumPoolSize/2?
P.S. Это логи не с моего компьютера, у меня такую ситуацию воспроизвести не удалось - у меня в данном случае количество активных потоков равняется 200, как и ожидалось. Может ли это быть зависимость от количества процессоров/количества ядер процессоров/какой-либо конфигурации ПО?


Ответ

"Есть очередь задач, создана следующим образом: ... new ThreadPoolExecutor(maximumPoolSize, maximumPoolSize, .."
Вы уверены, что maximumPoolSize - это одна переменная, и она имеет одно значение? Полагаю, что причина в том, что corePoolSize равен 100, а maximumPoolSize равен 200 и у Вас происходит следующее?
При добавлении нового потока в пул выполняет следующие действия последовательно:
Проверяет достигнут ли предел потоков, задаваемых переменной corePoolSize если можно еще запустить поток - запускает его. Если количество потоков равно или больше corePoolSize переходит к следующему шагу. Проверяет не заполнена ли очередь и если в ней еще есть место добавляет туда поток. Если очередь заполнена переходит к следующему шагу. Пытается увеличить количество работающих потоков до значения maximumPoolSize если можно добавить еще поток, то он добавляется и в нем и запускается задание. Если количество работающих потоков равно maximumPoolSize то выбрасывается исключение java.util.concurrent.RejectedExecutionException или вызывается перехватчик отклонения задачи определяемый программистом.
В вашем случае в виду того, что очередь увеличивается без ограничений к третьему шагу алгоритм никогда не переходит. Но можно «изменить» порядок следования шагов 2 и 3. Для этого необходимо создать очередь в которой мы переопределим вызываемый ThreadPoolExecutor метод offer так, чтобы он возвращал всегда false (очередь заполнена). Теперь нам нужно задать собственный перехватчик RejectedExecutionHandler. В перехватчике мы добавляем полученный поток в очередь. Пример изложенного выше в виде кода:
LinkedBlockingQueue queue = new LinkedBlockingQueue (100){ public boolean offer(Runnable e) {return false;} };
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(100, 200, 1, TimeUnit.MINUTES, queue, new RejectedExecutionHandler() { public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { try { executor.getQueue().put(r); } catch (InterruptedException e) { e.printStackTrace(); } } });

Комментариев нет:

Отправить комментарий