Примечание: это не попытка увидеть, была ли завершена задача, переданная в пул потоков, а завершение фактического потока.
Чтобы обнаружить утечки потоков, я хотел бы иметь код вида
val start = allThreads()
doStuff()
val end = allThreads()
assert start == end
Однако doStuff()
может использовать один или несколько пулов потоков, которые на самом деле очищаются с помощью вызова shutdownNow()
или аналогичного. Кажется, в ThreadPoolExecutor нет способа определить, все ли потоки были завершены. Такие вещи, как awaitTermination
, только следят за тем, чтобы все потоки дошли до того, что они обязательно завершат работу, но не до того, что они уже сделали.
В идеале решение не является хакерским, например, использование отражения для прямого доступа к внутренним объектам класса (из которого, конечно, мы можем получить все потоки, а затем соединить их все).
ОБНОВЛЕНИЕ: причина для этого
Если у вас есть большая кодовая база, разработанная в течение некоторого времени, у вас могут быть проблемы с утечками потоков. Люди могут не закрывать исполнителей должным образом, люди могут просто вызывать new Thread()
, люди могут вызывать сторонние библиотеки, которые запускают потоки, и либо код, либо код библиотеки не выходят из этих потоков. Ваши сборки потерпели неудачу из-за слишком большого количества потоков, запущенных в одном процессе, так как этот процесс может выполнить тысячи тестов, каждый из которых будет пропускать несколько потоков.
Чтобы предотвратить это, вы заставляете свои тесты проверять, чтобы потоки до теста и потоки после были одинаковыми. Это можно сделать, например, отражением, проверкой того, что каждый тестовый класс наследуется от базового класса, а затем в базовом классе, имеющем До / После для проверки потоков. Детали не
важно, но в основном у нас есть детектор утечки нитей, который не проходит тест на утечки нитей.
Теперь, если вы правильно используете ThreadPoolExecutor и вызываете shutdownNow, мы не хотим, чтобы тест не прошел из-за детектора утечки. Однако простое использование shutdownNow может привести к ложным срабатываниям, потому что даже если мы успешно вызвали shutdownNow и вернулись из остальной части кода и находимся в фазе After, где мы проверяем текущие потоки, потоки пула потоков в это время могут быть еще живы. Поэтому мы хотим каким-то образом гарантировать, что потоки в пуле уже вышли до возврата, чтобы избежать ложных срабатываний.