Java catch / finally块完全被跳过?

时间:2012-07-12 00:46:06

标签: java try-catch finally

我们有一个ThreadPoolExecutor-back任务执行模块。某些任务显然已在应用程序代码中完成,但工作程序代码以某种方式跳过所有try / catch / finally,然后继续执行下一个任务,导致前一个任务错过重要的状态报告代码。

就像在这个例子中一样,257832:5被线程8选中,但这个线程最终只是开始另一个任务。

2012-07-11 15:53:39,389 INFO  [pool-1-thread-6]: Task (258861:5) : Starting.
2012-07-11 15:53:39,389 INFO  [pool-1-thread-6]: A task running ### logged by app logic
2012-07-11 15:54:18,186 INFO  [pool-1-thread-6]: Task (258868:5) : Starting. ### pick up another suddenly!
2012-07-11 15:54:18,186 INFO  [pool-1-thread-6]: A task running ### logged by app logic
2012-07-11 15:54:18,445 INFO  [pool-1-thread-6]: Task (258868:5) : returned from Task.doWork.
2012-07-11 15:54:18,446 INFO  [pool-1-thread-6]: Task (258868:5) : finalizing.
2012-07-11 15:54:18,487 INFO  [pool-1-thread-6]: Task (258868:5) : notifying status result: 200.
2012-07-11 15:54:18,487 INFO  [pool-1-thread-6]: Task (258868:5) : Finished

ThreadPoolExecutor的Runnable)看起来很好。它看起来像

public void run() {
    log.info(String.format("Task (%s:%s) : Starting.", wfId, taskId));
    try {
        Object result = task.doWork(...); // call the application codes
        log.info(String.format("Task (%s:%s) : returned from Task.doWork.", wfId, taskId));
        status = "DONE";
    } catch (Throwable t) {
        log.error("Error executing task: " + taskId + " - " + className);
    } finally {
        log.info(String.format("Task (%s:%s) : finalizing.", wfId, taskId));
        // notify status to a server
        log.info(String.format("Task (%s:%s) : Finished", wfId, taskId));
    }
}
    // the task framework looks like
    // Use a queue size larger than numThreads, since the ThreadPoolExecutor#getActiveCount() call only returns an approximate count
    this.executor = new ThreadPoolExecutor(numThreads, numThreads, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(numThreads * 2));
    executor.execute(new TaskRunnable(...));

注意:

  1. 我们捕获了最终的Throwable,但两个任务之间没有记录异常
  2. 没有迹象表明调用了exit()或程序重启
  3. 第一个跳过所有日志行,无论是在调用应用程序代码之后的那个还是catch和finally块中的日志行,都跳过状态报告代码
  4. 这只是随机发生,概率很低;但是由于执行了大量任务,它仍然让我们头痛不已。

好像线程池执行器只是神奇地驱逐运行的runnable(否则它将需要一个InterruptedException,它将被捕获为Throwable; Java线程不会被非合作地停止,除非在关闭/退出期间)跳过所有块。我检查了ThreeadPoolExecutor javadoc,没有什么可以导致这样的事件发生。

可能发生了什么?

1 个答案:

答案 0 :(得分:0)

来自finally块的日志消息的一个可能的解释是,在finally块执行时抛出了异常:

  • 如果此时log为空,您将获得NPE。 (如果log被声明为final,您可以将此消除为可能原因。)

  • 根据对象的不同,您可以在wfIdtaskId对象'toString()方法中获得未经检查的例外。

  • Logger对象可能被破坏......


由于某种原因,您也可能正在查看错误的源代码。


另一个理论上的可能性是Android平台实现Thread.destroy()实际做某事,并且在线程上调用了它。如果根据原始javadoc实现了此DEPRECATED方法,则会发现finally块未执行。也可以从JVM外部执行相当的操作。但如果这是正在发生的事情,所有的赌注都会被取消!!