如果线程列表中的任何线程发生异常,则中断所有线程

2024-01-19

我正在使用 invokeAll() 调用线程列表。 AFAIK invokeAll() 仅当所有线程完成其任务时才会返回。

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

当所有线程完成时调用此方法

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

它会停止发生异常的线程,而不是剩余的线程。 如果任何线程抛出异常,是否有办法停止所有其他线程? 或者我必须提交每个任务而不是 invokeAll() 吗?

我尝试在 invokeAll() 上使用 invokeAny() 代替,但没有取消剩余的任务 invokeAny() :如果其中一项任务完成(或引发异常),则其余的 Callable 任务将被取消。 参考:http://tutorials.jenkov.com/java-util-concurrent/executorservice.html 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;
                    }

更新1:

按照 waltersu 的建议我尝试过

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

当异常发生时这不会停止


你必须submit()一件一件地,而不是调用全部(),然后检查是否Future有异常。

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

更新 1:(回答 op 的更新 1 问题)

这是因为你的任务有一个很长的循环,不会检查中断,这使得你的任务不可取消。那你怎么阻止它呢?我认为你必须修改其他任务才能取消它们。作为官方文档 https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html says:

如果线程长时间不调用抛出 InterruptedException 的方法怎么办?然后它必须定期调用 Thread.interrupted,如果收到中断则返回 true。例如:

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

如果您不想修改任务并希望它快速停止怎么办?有一种方法可以停止不可取消的线程。它是线程.stop()。但是,首先,如果不使用反射,则无法从线程池中获取线程。此外,它已被弃用,因为根据该协议,“它本质上是不安全的”javadoc https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#stop().

因此,最佳实践(我认为)是检查任务(或部分代码)中的中断,该中断既不可取消又需要花费很长时间才能完成。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果线程列表中的任何线程发生异常,则中断所有线程 的相关文章

随机推荐