我们有一个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(...));
注意:
好像线程池执行器只是神奇地驱逐运行的runnable(否则它将需要一个InterruptedException,它将被捕获为Throwable; Java线程不会被非合作地停止,除非在关闭/退出期间)跳过所有块。我检查了ThreeadPoolExecutor javadoc,没有什么可以导致这样的事件发生。
可能发生了什么?
答案 0 :(得分:0)
来自finally块的日志消息的一个可能的解释是,在finally块执行时抛出了异常:
如果此时log
为空,您将获得NPE。 (如果log
被声明为final
,您可以将此消除为可能原因。)
根据对象的不同,您可以在wfId
或taskId
对象'toString()
方法中获得未经检查的例外。
Logger
对象可能被破坏......
由于某种原因,您也可能正在查看错误的源代码。
另一个理论上的可能性是Android平台实现Thread.destroy()
实际做某事,并且在线程上调用了它。如果根据原始javadoc实现了此DEPRECATED方法,则会发现finally
块未执行。也可以从JVM外部执行相当的操作。但如果这是正在发生的事情,所有的赌注都会被取消!!