【问题标题】:Why executor is not running out of available threads when its threads ends up with exceptions?当它的线程以异常结束时,为什么执行程序没有用完可用线程?
【发布时间】:2018-08-11 17:58:21
【问题描述】:

在以下场景中,我的任务会引发异常。我只是在一个请求之后,我的池将无法处理任何进一步的请求,但它没有发生。在这种情况下线程池的行为如何?从 Pool 线程到主应用程序线程如何进行异常通信?

public class CallableClass implements Callable<String> {

    @Override
    public String call() throws Exception {
        throw new RuntimeException();
    }

}

class Test {
      ExecutorService executor = Executors.newFixedThreadPool(1);

      public void execute(){  
         try {
            System.out.println(executor);
            Future<String> future = executor.submit(new Task());
            System.out.println(executor);

            future.get();
        }catch(Exception e) {
           System.out.println(executor);
           e.printStackTrace();
        }
     }

  }

【问题讨论】:

    标签: java multithreading threadpool executorservice threadpoolexecutor


    【解决方案1】:

    您可以通过打印当前正在执行的线程的名称来检查它:

    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        ...
    }
    
    1. 线程池在这种情况下表现如何?

    worker 通知 executor 服务它在工作时发生的异常。但是没有理由从ThreadPoolExecutor#workers 集合中删除该工作人员。如果有需要,它将继续工作。

    您不应该看到执行器服务出现任何故障。如果发生错误,它将用有效的工作人员(或线程)替换无效的工作人员(或线程):

    如果任何线程在关闭前的执行过程中因失败而终止,如果需要执行后续任务,新的线程将取代它。

    ExecutorService.newFixedThreadPool(int) [JDK 9]


    1. 异常通信如何从池线程到主应用程序线程?

    Callable#call 抛出的任何异常都被 ExecutionException 包装并弹出给调用者:

    @throws ExecutionException 如果计算抛出异常

    Future.get()[JDK 9]

    检查ExecutionException#getCause 是否为RuntimeException 实例的示例:

    } catch (ExecutionException e) { 
        Throwable cause = e.getCause();
        if (cause != null && cause instanceof RuntimeException) {
            System.out.println("A RuntimeException was thrown.");
        }
    }
    

    【讨论】:

    • 你好 Andrew,我将任务代码更新为:class Task implements Callable{ @Override public String call() throws Exception { System.out.println(Thread.currentThread()+"> >>>>>>>>>>>>>>"+Thread.currentThread().getName());抛出新的 RuntimeException();但是对于每个请求,它都会打印相同的线程名称。这意味着即使在执行上一个任务时出现异常,也会重复使用同一个工作人员。
    • “从 Callable#call 抛出的任何异常都被 ExecutionException 包装并弹出给调用者”。很抱歉我没有收到这个。
    • @Jaraws,它会向您调用get 的线程抛出new ExecutionException(yourActualException)。然后你调用 fetch yourActualException by exception.getCause()
    • 你好@Andrew,如果池线程抛出异常,那么池必须用完它唯一的线程。因为,这里没有发生,所以必须有一些通道,这个池线程必须通过它把它的异常传递给主线程并返回到它的池。
    • @Jaraws,线程池永远不会抛出异常,你的任务可能会抛出它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 2017-08-01
    相关资源
    最近更新 更多