Reputation: 29
So I have this Java piece of code where I need to do some work on a bunch of items. I decided to parallelize this to get some extra boost and I though to use a ThreadPoolExecutor. The problem is that the work I need to do can throw an exception...
Now I would like to shutdown the entire job to stop as soon as an error is encountered and report it back so I can handle it. Looking online, I found that the normal way this should be done is via ExecutorCompletionService and analyzing the Future results. However, this won't let me shut everything down when the first error comes by, as there is no way to loop over based on which task finishes first...
So I did something that I thought was rather hacky and I'm curious if there is a better way to handle this. What I did was:
1) Have each Runnable that I will execute have a field for the Throwable that it might execute. 2) Override the TPE's "afterExecute" method and check if any checked exception got thrown (which gets recorded in the Runnable) or any unchecked one gets thrown (which should be reported in the second parameter of this method). If any did, then I issue a shutdownNow() on the TPE.
Again, this seems a bit hacky and I am wondering if there is something I am missing. Thanks in advance!
Upvotes: 3
Views: 638
Reputation: 5326
Look at ExecutorService.invokeAny:
Executes the given tasks, returning the result of one that has completed successfully (i.e., without throwing an exception), if any do. Upon normal or exceptional return, tasks that have not completed are cancelled. The results of this method are undefined if the given collection is modified while this operation is in progress.
It looks it does the exact same thing you are trying to do... if I understood your problem correctly.
However for cancel to do anything, you have to make your Callable
tasks interrupt aware. But that applies no matter how you try to cancel your tasks.
EDIT:
This is not what you need; I misread the javadoc. Here's another solution: you could put all your Future
's in a list and then have a semi-busy while loop where you check periodically on each futureList.get(i).get(100, TimeUnits.MILLISECONDS)
and you can catch an exception and act accordingly. However, this no more "elegant" than your solution. It seems that afterExecute
was made to do what you want anyway.
Upvotes: 2