如果任务遇到异常,则会禁止其进一步执行。为什么?

时间:2013-11-13 03:35:22

标签: java multithreading

scheduleAtFixedRatescheduleWithFixedDelay的文档说:

  

如果任务的任何执行遇到异常,则后续   执行被压制

假设我的任务是为了做一些网络工作而没有找到主机。这些任务不会再被执行吗?主机可能在下一刻重新上线。

假设文档正在讨论的是RuntimeException的实例,就像数组索引超出范围一样,任务永远不会再被执行?如果我希望他们继续执行该怎么办?

3 个答案:

答案 0 :(得分:3)

  

任务永远不会再被执行吗?

这就是“后续处决被压制”意味着,不是吗?

  

如果我希望他们继续执行该怎么办?

不要让RuntimeExceptionsErrors逃脱。

答案 1 :(得分:1)

检查由Scheduler执行的Runnable操作中的未捕获异常。默认情况下,JVM不会捕获它们并且线程崩溃时会被忽视。


我建议使用自定义ScheduledThreadPoolExecutor,如下所示:

static class MyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
    public MyScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) {
        super(corePoolSize, threadFactory);
    }

    @Override
    public ScheduledFuture<?> schedule(Runnable command, long delay,TimeUnit unit) {
        return super.schedule(new SheduleExceptionCatcher(command), delay, unit);
    }


    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay, long period, TimeUnit unit) {
        return super.scheduleAtFixedRate(new SheduleExceptionCatcher(command), initialDelay, period, unit);
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay, long delay, TimeUnit unit) {
        return super.scheduleWithFixedDelay(new SheduleExceptionCatcher(command), initialDelay, delay, unit);
    }


    /** Wrap for Runnable - for error catching */
    private static class SheduleExceptionCatcher implements Runnable {
        private Runnable task;
        public SheduleExceptionCatcher(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            try {
                task.run();
            } catch (Throwable e) {
                System.err.println("" + e); // or some logger probably
            }
        }
    }
}

进行一些测试:

public static void main(String[] args) {
    new MyScheduledThreadPoolExecutor(2, new PriorityThreadFactory("GeneralSTPool", Thread.NORM_PRIORITY)).scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            throw new RuntimeException("Test Error");
        }
    },3000, 3000, TimeUnit.MILLISECONDS);

    while (true){}
}

将打印

java.lang.RuntimeException: Test Error
java.lang.RuntimeException: Test Error
java.lang.RuntimeException: Test Error
java.lang.RuntimeException: Test Error
java.lang.RuntimeException: Test Error

因此,即使抛出错误,您的任务也会永久执行。

答案 2 :(得分:1)

当我忘记在Runnable内捕获异常时,不明白崩溃发生在哪里非常烦人。实际上我不需要忽略所有这些异常,我只需要确保不要忽视它们。为此,我创建了CatchyRunnable类,它是Runnable的包装器,它记录异常并在需要时传播它们:

executorService.submit(new CatchyRunnable(new Runnable() {
    @Override
    public void run() {
        throw new RuntimeException("log me");
    }
});

您可以通过应用工厂方法模式使用更简洁的语法,我只是计划与lambdas一起使用:

executorService.submit(new CatchyRunnable(() -> {
     throw new RuntimeException("log me");         
});