4

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;
                    }

Update 1:

As suggested by waltersu I tried

ExecutorService threadExecutor = Executors.newFixedThreadPool(3);
              CompletionService<Object> completionService = new ExecutorCompletionService<Object>(threadExecutor);
              List<Future<Object>> futures = new ArrayList<Future<Object>>();
              futures.add(completionService.submit(new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    String s=null;
                //  Thread.sleep(1000);
                  for(int i=0; i < 1000000; i++){
                        int j =10 ;
                        if(i==100)
                        {

                        s.toString();
                        }

                        System.out.println("dazfczdsa :: " + i);
                    }
                  //throw new Exception("This is an expected Exception");
                return s;
                }
              }));
              futures.add(completionService.submit(new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    for(int i=0; i < 1000000; i++){
                        int j =0 ;
                        j= j+2;
                        System.out.println("dasa :: " + i);
                    }
                  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!");
                  f.cancel(true);
                  threadExecutor.shutdownNow();
                  break;
                }
              }
              System.out.println("Main exists");

this does not stop when exception occurs

happy
  • 2,550
  • 17
  • 64
  • 109
  • threadExecutor.notifyAll() to interrupt all threads – Akash Lodha Jun 17 '16 at 10:30
  • @AkashLodha `notifyAll()` from `Object` "Wakes up all threads that are waiting on this object's monitor". The threads are not waiting on any particular object's monitor, are they? What am I missing? – davmac Jun 17 '16 at 10:33
  • I am assuming that the threadList are threads wanting a lock on same object. – Akash Lodha Jun 17 '16 at 10:37
  • If you intend to dismiss all work if one thread is errornous, you could `future.cancel(true)` the tasks - which will interrupt the thread if the task is running. – Fildor Jun 17 '16 at 10:40
  • I am not getting control in the parent thread if exception occurs.It only comes after finishing all threads. – happy Jun 17 '16 at 10:41
  • So what do you want to do? Do you want to keep that behavior and just leave the loop on exception? Or do want to cancel all work as soon as any thread encounters the exception? In latter case you need to add some kind of callback to gain the control and cancel the tasks. – Fildor Jun 17 '16 at 10:46
  • Can you add some more code, indicating where exactly the exception is thrown? – Fildor Jun 17 '16 at 11:13
  • want to cancel all work as soon as any thread encounters the exception – happy Jun 17 '16 at 11:34
  • `InvokeAny` won't help you since you want all of them executed (except when there is an exception). – Fildor Jun 17 '16 at 11:34
  • Is the work actually "cancelable"? If you have small loops you could check a "canceled" flag. If your work goes into long lasting block , you might want to use interruption. You also can support checking interruption instead of a special flag ... – Fildor Jun 17 '16 at 11:38
  • Calling cancel(mayInterruptIfRunning = true) of all *futures* works fine for me. With your approach, I need to call threadExecutor.shutdown() so my application can exist. But why do you interrupt() main thread? – waltersu Jun 17 '16 at 12:42

4 Answers4

3

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");
}

Update 1: (To answer op's update 1 question)

That's because your task has a long loop which doesn't check the interruption, which makes your task noncancelable. Then how do you stop it? I think you have to modify your other tasks to make them cancelable. As the official doc says:

What if a thread goes a long time without invoking a method that throws InterruptedException? Then it must periodically invoke Thread.interrupted, which returns true if an interrupt has been received. For example:

for (int i = 0; i < inputs.length; i++) {
    heavyCrunch(inputs[i]);
    if (Thread.interrupted()) {
        // We've been interrupted: no more crunching.
        return;
    }
}

What if you don't want to modify your task and also want it to stop quickly? There's a method you can stop a noncancelable thread. It's Thread.stop(). But, at first, you can't get the thread from threadpool without using reflection. Besides, it's deprecated because "it is inherently unsafe" according to the javadoc.

So, the best practice(I think) is to check the interruption in your task(or part of code) which is both noncancelable and spending a long time to finish.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
waltersu
  • 1,191
  • 8
  • 20
  • Update: If all tasks complete successfully, still need to call threadExecutor.shutdown() so application can exists. Because http://stackoverflow.com/a/20057584/4493265 – waltersu Jun 17 '16 at 13:16
  • Pls check my Update 1: in question..if exception occurs ut does not terminate the other thread – happy Jun 18 '16 at 10:41
0
for(Future<Object> fut : future){
    try {
            System.out.println(fut.get());
    } 
    catch (InterruptedException | ExecutionException e) {
        Thread.currentThread().interrupt();
        // or notify all here
    } 
Akash Lodha
  • 100
  • 9
0

You could Invoke Wrappers that take your work-runnables and a reference to the Executor they are going to be invoked by. On exception, you can then cause immediate shutdown from within run().

class ExceptionHandlingWrapper implements Runnable{
    private ExecutorService es;
    private Runnable childRunnable;

    // CTOR taking an ExecutorService and a Runnable
    public ExceptionHandlingWrapper ( ExecutorService es, Runnable work ){
         this.es = es;
         this.childRunnable = work;
    }

    @Override public void run(){
        try{
           childRunnable.run();
        }
        catch(Exception ex){
            // Todo: LOG IT!
            es.shutdownNow();
        }
    }
}

This also works with Callables of course.

Fildor
  • 14,510
  • 4
  • 35
  • 67
0

Few suggestions:

  1. Remove invokeAll and submit all tasks to ExecutorService.
  2. Catch the Exception from get() on Future and use shutdown & shutdownNow as explained in these questions:

How to stop next thread from running in a ScheduledThreadPoolExecutor

How to forcefully shutdown java ExecutorService

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211