Note: This not trying to see if a task that has been submitted to the thread pool has completed, but whether the actual thread has exited.
In order to detect thread leaks I'd like to have code of the form
val start = allThreads()
doStuff()
val end = allThreads()
assert start == end
However, doStuff()
may use one or more thread pools, which are actually cleaned up by calling shutdownNow()
or similar. There doesn't seem to be a way in a ThreadPoolExecutor to detect whether all threads have terminated. Things like awaitTermination
only make sure that all threads have gotten to the point that they will definitely exit, but not that they already have.
Ideally the solution is not hacky such as using reflection to access the internals of the class directly (from which of course we can get all threads then join them all).
UPDATE: The reason for doing this
If you have a large codebase developed over some time you may have a problem with thread leaks. People may not shut down executors appropriately, people may just call new Thread()
, people may call third party libraries that start threads and either the code or the library's code doesn't exit those threads. Your builds have failed due to way too many threads running in a single process as that process may run thousands of tests each of which would leak a few threads.
To prevent this, you force your tests to all check that the threads before the test and threads after are the same set. This can be done e.g. by reflection, verifying that every test class inherits from a base class, then in the base class having Before/After to verify threads. The details aren't important but basically we have a thread leak detector that fails the test on leaked threads.
Now if you are properly using a ThreadPoolExecutor and calling shutdownNow, then we do not want the test to fail due to the leak detector. However, just using shutdownNow can cause false positives because even though we successfully called shutdownNow and returned from the rest of the code and are in the After phase where we check current threads, the thread pool threads may still be alive at that time. Therefore we want some way to guarantee that the threads in the pool have already exited before returning, in order to avoid these false positives.