I submit Callable tasks (using submit()) to an implementation of ExecutionService. Very occasionally I seem to be encountering a deadlock but cannot work where or why it is happening so I would like to set a timeout on the task, I'm not clear how do it ?
Should I
- Use invokeAny() on the ExecutionService instead of submit() when submitting the task and set a timeout. I submit many tasks one at a time over time using submit(), can I use invokeAny() like this as well, I'm cautious because I cannot understand why there isn't a submit() method that takes a timeout.
- Modify keepAliveTime in my constructor of my ExecutorService (but I think this is doing something else
- Modify my actual Callable implementation, but if its is deadlocked it cant undeadlock itself.
Option 1 seems the only viable solution but is it ?
More details
I thought it may be worth explaining how the process works in more detail in case it helps with solution.
Callable task P1 is started and works on a folder, and all the files and folders within it and starts grouping the songs into groups, its runs inside ExecutorService ES1, and just the one single instance of P1 is submitted to ES1.
We also have three other Callable classes: P2, P3, and P4 - each of these has their own associated Executor Service, ES2, ES3, Es4). Once P1 has created a group it then submits a task to the associated ES with the group passed as data, i.e. it could submit an instance of P2 to E2, P3 or to P3 or P4 to E4, which one it chooses depends on details of the grouping, P2, P3 and P4 all do different things.
Assume it had submitted an instance of P2, P2 will finish processing by submitting P3 to E3 or P4 to E4. Its a one way pipeline P3 can only submit to P4, and once all tasks have been submitted to P4 and P4 has finished all the tasks the processing has finished.
We complete processing by constructing ES1, ES2, ES3 and ES4, submitting task to P1, then calling shutdown() on each ExecutorService in turn so, shutdown() will not return until P1 has finished submitting all groups, it then calls shutdown() on ES2 which will not return until ES2 has cleared it queue of P2 tasks ecetera.
Very occasionally everything just stops Im assuming some process is stopping other processes from continuing, so at this point I want a way of cancelling processes that take too long so others can continue, this is significantly less bad then it just hanging indefinitently
Update on Answer
I tried using invokeAny() as suggested, it sort of works. If P1 submits an instance of P2 to E2 it then waits before completing, that is sort of okay because when using submit() it just returns any way there it does not further processing but there are two issues:
Each ExecutorService uses a bounded queue of 500, the idea being that if P2 is much slower than P1 we dont keep stacking things onto ES2 and eventually run out of memory. So now P1's don't finish until the task they call has finished the queues are effectively smaller because they dont just consist of tasks waiting for a slot on ES2 to finish but they contain tasks that have already submitted to ES2 but are waiting for it to finish.
The pipeline is chained so if we use invokeAny on tasks submitted from P1, and tasks submitted from P2 and P3 and P4 then when a task is submitted from P1 to P2 it will not return until subsequent processing completes from E4 !