【问题标题】:Java Timer class: timer tasks stop to execute if in one of the tasks exception is thrownJava Timer 类:如果在其中一个任务中抛出异常,则计时器任务停止执行
【发布时间】:2021-09-13 00:20:58
【问题描述】:
new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
       System.out.println("run");
       throw new SomeRandomException();
    }
 }, 1000, 1000);

输出:运行(抛出异常)

这是问题所在:我需要一个计时器任务来检查数据库(或其他)中的特定条件。它工作正常,但有时数据库(或其他)返回一些错误,抛出异常并且计时器崩溃,然后不再执行单个计时器任务。是否有一些 Timer 实现在run() 中引发异常后继续工作。

我可以

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        try {
            System.out.println("run");
            throw new SomeRandomException();
        } catch (Exception e) {
            System.out.println("dummy catch");
        }
    }
}, 1000, 1000);

但这似乎很蹩脚。

另一种选择是编写我自己的 Timer 类实现,吞下 run 方法的异常(这似乎也不正确)。

【问题讨论】:

  • 你也需要抓住Errors,否则他们也会默默地杀死你的任务。
  • 在运行中记录和捕获异常有什么问题?

标签: java timer


【解决方案1】:

使用ScheduledExecutorService。它与 Timer 的作用相同,但修复了它的弱点(就像你遇到的那个)。

【讨论】:

  • 不幸的是“如果任务的任何执行遇到异常,后续执行将被抑制。” - 来自docs.oracle.com/javase/6/docs/api/java/util/concurrent/…, long, long, java.util.concurrent.TimeUnit)
  • 是的,这个特定的任务会停止运行,但不会导致执行器崩溃,其他任务仍然在调度中。但我同意您仍然必须捕获任何可能发生的异常,并且不得导致任务调度被中止。您可能想要创建一个 CatchAllRunnable 可重用类。
【解决方案2】:

使用ExecutorService;,您可以处理编译时和运行异常。

Handling exceptions from Java ExecutorService tasks
How is exception handling done in a Callable

ThreadPoolExecutor.java

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

【讨论】:

    【解决方案3】:

    老实说,我在 timertask 运行中发现异常捕获和日志没有任何问题,特别是如果您捕获所有异常并正确记录它们,这样它们就不会丢失。

    fun Timer.schedule(delay: Long = 0, function: () -> Unit): TimerTask {
        val task = object : TimerTask() {
            override fun run() {
                try {
                    function()
                } catch (e: Throwable) {
                    logError(e)
                }
            }
        }
        schedule(task, delay)
        return task
    }
    

    其他选项是捕获重新抛出并重新创建 Timer 实例可能吗?但我不知道这个用例,在 android 上我可能会以某种方式实现它:

    private var timer = Timer()
    
    schedule(delay: Long = 0, function: () -> Unit): TimerTask {
            val task = object : TimerTask() {
                override fun run() {
                    try {
                        function()
                    } catch (e: Throwable) {
                        later { timer = Timer() }
                        throw e
                    }
                }
            }
            timer.schedule(task, delay)
            return task
        }
    

    【讨论】:

      猜你喜欢
      • 2019-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多