What is terminating my Java ExecutorService
For a long time I thought the problem must be with my code, I then started thinking the issue was with ThreadPoolExecutor
, but adding debugging to my own version of runWorker()
showed the problem was indeed my own code.
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
MainWindow.userInfoLogger.severe("-----------------------"+workQueue.size());
From this I could see that whilst the worker queue was getting generally longer and matched the value of
MainThreadAnalyzer.pendingItems -noOfWorkerThreads
at a particular point the two values diverged, and this was when the SongLoader process (which mistakenly I had not really considered) finished. So MainThreadAnalyzer was continuing to submit work increasing the value of pendingItems , but the work queue size of the Executor was getting smaller.
This lead to realization that the Executor had shutdown() alot earlier, but we hadn't realized this because only check latch after songloader had closed.
And the reason it had shutdown was because early on the MainAnalyzerThread
was completing the work more quickly then SongLoader
was submitting it so the value of pendingItems was temporarily set to zero allowing the latch to be closed.
The solution is as follows
Add a boolean flag to indicate when songLoader has completed and only allow latch to be closed once this flag is set.
private boolean songLoaderCompleted = false;
public void workDone(Callable task)
{
int remainingItems = pendingItems.decrementAndGet();
MainWindow.logger.severe(">>WorkDone:" + task.getClass().getName() + ":" +remainingItems);
if (remainingItems == 0 && songLoaderCompleted)
{
MainWindow.logger.severe(">Closing Latch:");
latch.countDown();
}
}
Then in main thread set this flag once SongLoader has completed
//Start SongLoader
ExecutorService songLoaderService = SongLoader.getExecutorService();
songLoaderService.submit(loader);
//SongLoader uses CompletionService when calls LoadFolderWorkers so shutdown wont return until all folder
//submissions completed to the MainAnalyserService
songLoaderService.shutdown();
songLoaderService.awaitTermination(10, TimeUnit.DAYS);
MainWindow.userInfoLogger.severe(">Song Loader Finished");
//Were now allowed to consider closing the latch because we know all songs have now been loaded
//so no false chance of zeroes
analyserService.setSongLoaderCompleted();
//Just waits for all the async tasks on the list to complete/fail
analyserService.awaitCompletion();
MainWindow.userInfoLogger.severe(">MainAnalyser Completed");
//This should be immediate as there should be no tasks still remaining
analyserService.getExecutorService().shutdown();
analyserService.getExecutorService().awaitTermination(10, TimeUnit.DAYS);