Страницы

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

воскресенье, 12 января 2020 г.

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

#java #очередь_задач


Есть очередь задач, создана следующим образом:

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, как и ожидалось.
Может ли это быть зависимость от количества процессоров/количества ядер процессоров/какой-либо
конфигурации ПО?
    


Ответы

Ответ 1



"Есть очередь задач, создана следующим образом: ... 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(); } } });

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

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