2

的文档scheduleAtFixedRatescheduleWithFixedDelay说:

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

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

假设文档所说的是一个实例RuntimeException,比如数组索引越界,任务将永远不会再次执行吗?如果我希望他们继续执行怎么办?

4

3 回答 3

3

任务将永远不会再次执行吗?

这就是“禁止后续处决”的意思,不是吗?

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

不要让RuntimeExceptions他们Errors逃脱。

于 2013-11-13T05:24:33.580 回答
1

检查由调度程序执行的 Runnable 操作中未捕获的异常。默认情况下,JVM 不会捕获它们并且线程在不被注意的情况下崩溃。


我建议使用 custom 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

因此,尽管抛出错误,您的任务仍将永远执行。

于 2013-11-13T03:56:23.367 回答
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");         
});
于 2013-11-13T08:24:04.863 回答