有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

runnable中的java异常似乎会杀死线程池

我有一个runnable,我想定期运行。在特定的运行中,我相信runnable遇到了空指针,但控制台上没有显示异常。在那次失败的运行之后,它再也不会运行了。我有两个问题:

  1. 如果有空指针,为什么控制台上不显示
  2. 即使某个特定的运行失败,我如何让计划的任务在将来再次运行
scheduler = Executors.newScheduledThreadPool(1);
MyRunnable mr = new MyRunnable(this.data);
scheduler.scheduleWithFixedDelay(mr, 0, STATUS_SENDER_PERIOD, TimeUnit.MILLISECONDS);

共 (1) 个答案

  1. # 1 楼答案

    回答你的问题

    1)之所以看不到任何类型的异常,是因为在FutureTask#run内调用的FutureTask#setException有效地吞噬了它。为了能够记录异常,您应该创建一个新类,扩展ScheduledThreadPoolExecutor并覆盖afterExecute方法,如下所示:

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        if (t == null && r instanceof Future<?>) {
            try {
                Object result = ((Future<?>) r).get();
             } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
             } catch (ExecutionException e) {
                t = e;
             }
        }
    
        if (t != null) {
            t.printStackTrace();
        }
    }
    

    或者直接在返回的ScheduledFuture上调用get,如下所示:

    var executor = Executors.newSingleThreadScheduledExecutor();
    var future = executor.scheduleAtFixedRate(new MyRunnable(null), 1, 1, TimeUnit.SECONDS);
    
    try {
        future.get();
    
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    

    2)重新运行失败的runnable的最简单方法是:

    while (true) {
        try {
            future.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
         }
    }
    

    但我认为这种方法并不是最干净的。正确地编写Runnable#run方法来处理异常将是一个更好的解决方案