happy happy - 5 months ago 30
Java Question

Interrupt all threads if exception occurs in any of the thread among the thread list

I am invoking List of threads using invokeAll(). AFAIK invokeAll() will return only when all the threads completes its task.

ExecutorService threadExecutor = Executors.newFixedThreadPool(getThreadSize());
List<Future<Object>> future = w_threadExecutor.invokeAll(threadList);


this is called when all threads finishes

for (Future<Object> w_inProgressThread : w_future)
{
//


It stops the thread in which exception occured and not the remaining one.
Is there a way to stop all the other threads if any of the thread throws exception?
Or do I have to submit each task instead of invokeAll()??

I tried using invokeAny() instead on invokeAll() but does not cancell remaining task
invokeAny() : If one of the tasks complete (or throws an exception), the rest of the Callable's are cancelled.
Ref : http://tutorials.jenkov.com/java-util-concurrent/executorservice.html

Update :

CompletionService<Object> completionService = new ExecutorCompletionService<Object>(w_threadExecutor);
List<Future<Object>> futures = new ArrayList<Future<Object>>();
for(Thread w_mt : threadList)
{
futures.add(completionService.submit(w_mt));
}
for (int numTaken = 0; numTaken < futures.size(); numTaken++) {
Future f = completionService.take();
try {
Object result = f.get();
System.out.println(result); // do something with the normal result
} catch (Exception e) {
System.out.println("Catched ExecutionException, shutdown now!");
//threadExecutor.shutdownNow();
Thread.currentThread().interrupt();

for (Future<Object> inProgressThread : futures)
{
inProgressThread.cancel(true);
}
break;
}


and in the child

private volatile boolean cancelled = false;
@Override
public Object call() throws Exception
{
try
{
while (!Thread.currentThread().isInterrupted() && !cancelled)
{
\\
}

public void cancel() {
cancelled = true;
}


I tried this and it takes the control to the parent thread but does not stops the other thread

Answer

You have to submit() one by one, instead of invokeAll(), then check if the Future has Exception.

public static void main(String[] args) throws InterruptedException {
  ExecutorService threadExecutor = Executors.newFixedThreadPool(3);
  CompletionService<Object> completionService = new ExecutorCompletionService<>(threadExecutor);
  List<Future<Object>> futures = new ArrayList<>();
  futures.add(completionService.submit(new Callable<Object>() {
    @Override
    public Object call() throws Exception {
      Thread.sleep(1000);
      throw new Exception("This is an expected Exception");
    }
  }));
  futures.add(completionService.submit(new Callable<Object>() {
    @Override
    public Object call() throws Exception {
      Thread.sleep(3000);
      return "My First Result";
    }
  }));

  while (futures.size() > 0) {
    Future f = completionService.take();
    futures.remove(f);
    try {
      Object result = f.get();
      System.out.println(result);  // do something with the normal result
    } catch (ExecutionException e) {
      System.out.println("Caught exception from one task: " + e.getCause().getMessage() + ". shutdown now!");
      threadExecutor.shutdownNow();
      break;
    }
  }
  System.out.println("Main exists");
}
Comments