В макушке головы я могу вспомнить пару подходов, которые я начну описывать здесь.Если вам нужно более подробное объяснение, я был бы рад разработать.Обратите внимание, что я NOT попытался написать код для проверки любого из них (пока), поэтому возьмите их с крошкой соли.
Первый подход основан на центральном диспетчере (основной поток) для координации пула рабочих потоков и очереди «работ» (из папок).Центральный диспетчер инициализирует пул потоков до минимального размера и назначает корневую папку первому рабочему потоку, а затем сигнализирует о его пробуждении.
Каждый рабочий поток запускается в состоянии ожидания, зацикливаясь до тех пор, пока не получит 'проснись 'сигнал.Затем он проверяет, была ли ему назначена папка для обработки, и начинает перебирать содержимое этой папки.Рабочий поток отправляет любые файлы, которые соответствуют шаблону, в список «найден» (или просто печатает его в System.out
).
Любые подпапки добавляются обратно в очередь «работа» (и основной потоксигнал).После этого рабочий поток возвращается в состояние «бездействия» (и основной поток снова получает сигнал).После пробуждения ему должна быть назначена новая папка, которую он начинает обрабатывать таким же образом.В противном случае поток может завершить сам себя.
Основной поток ожидает получения сигнала от любого рабочего потока.Сначала проверяется, пуста ли рабочая очередь.Если нет, то он проверяет, есть ли рабочие потоки, которые простаивают.Пока есть свободные рабочие потоки (а рабочая очередь не пустая), вытолкните первую папку из рабочей очереди, назначьте ее этому потоку и подайте сигнал на пробуждение.Затем основной поток возвращается к ожиданию.
Если нет свободных потоков, то проверьте текущий размер пула потоков относительно максимального настроенного размера.Если пул уже на максимуме, то основной поток возвращается в спящий режим (в основном, ожидая, пока поток не станет свободным).В противном случае, пока пул не максимален, создайте новый поток, добавьте его в пул и назначьте ему первую папку в рабочей очереди, а затем включите его.
Если основной поток активируетсяс пустой рабочей очередью, сначала она проверяет, есть ли свободные потоки, и пул рабочих потоков превышает настроенный минимум.Если это так, основной поток может выбрать для активации свободные потоки (без назначенной папки, поэтому они будут прерваны) и удалить их из пула.Если пул потоков уже минимален, то основной поток снова возвращается в режим ожидания.Обратите внимание, что этот шаг «сокращения» может быть ненужной оптимизацией (поскольку рабочие потоки не должны все равно потреблять циклы ЦП).
Если все потоки простаивают и рабочая очередь пуста, тогда главный поток знает, что это сделано, и может дать сигнал всем оставшимся рабочим потокам проснуться и завершить себя.
Уловка здесь заключается в передаче сигналов между основным потоком и рабочими потоками, исинхронизация в рабочей очереди (и, возможно, корзина «найденные файлы»).
(Кроме того, чтобы немного упростить ситуацию, можно выбрать пул потоков фиксированного размера.)
Альтернативный подход не включает центральный диспетчер, но использует фиксированный пул рабочих потоков, спящих в течение случайных интервалов, периодически просыпаясь, чтобы проверить, есть ли в рабочей очереди элемент или б) вся работа выполнена.
Основной поток просто инициализирует пул потоков, помещает корневую папку в начало рабочей очереди, затем запускает всеOrker темы.Затем он ожидает сигнала о том, что вся работа выполнена, и он может очиститься (прервать все оставшиеся рабочие потоки, чтобы разбудить их и завершить себя).
Каждый рабочий поток запускается в режиме ожиданиясостояние и проверяет рабочую очередь.Первый поток должен увидеть корневую папку, которую он вытаскивает из очереди и начинает обрабатывать, как описано выше.Все остальные потоки при запуске должны увидеть пустую очередь и перейти в спящий режим.
Когда рабочий поток просыпается, он проверяет, есть ли в рабочей очереди еще какие-либо папки, подлежащие обработке, и, если это так, работает с ним, устанавливая его флаг 'idle' в false
.Когда это сделано с текущей папкой, он снова проверяет рабочую очередь.Если рабочая очередь пуста, она устанавливает свой флаг "бездействия".
Когда рабочий поток находит пустую очередь (либо после пробуждения, либо после обработки), он проверяет все остальные потоки, если они 'в режиме ожидания.Если он обнаружит, что хотя бы еще один поток все еще работает, он переходит в спящий режим на произвольный интервал.
Если все остальные потоки находятся в режиме ожидания и рабочая очередь пуста, поток может завершить свою работу.Перед этим он прерывает или сигнализирует о главном потоке, чтобы основной поток мог выполнить очистку для остальных потоков.
Этот подход также можно адаптировать для использования пула потоков гибкого размера, который может динамическиувеличиваться или уменьшаться по мере необходимости, но это просто помещает более сложную логику в рабочие потоки, в которую я пока не буду вдаваться.