3

ScheduledExecutorService在 JEE 环境中获得了任务调度。其中一些任务在被中断时会打开资源ScheduledExecutorService.shutdownNow()(例如,使用第三方库(如 Lucene)打开文件)。

我知道一个线程可能不会自己停止执行:停止线程必须使用的方法是查看中断标志并停止方法执行,如果线程被阻塞(例如wait(),sleep()等)或者如果在可中断的通道中进行一些 IO 操作,Thread.interrupt()则会InterruptedException上升。在这两种情况下,都必须执行 finally 块。请参阅:http: //download.oracle.com/javase/1,5.0/docs/api/java/lang/Thread.html#interrupt%28%29

显然,我已经尝试在Task 类中使用一个实现非常好的finally 块来释放资源,但是在某些环境(例如CentOS)中,当线程中断时,finally 块不会被执行。然后我在官方 Java 文档中发现了这个非常酷的注释:

注意:如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。同样,如果执行 try 或 catch 代码的线程被中断或杀死,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。

所以,我需要的是对所有计划任务的引用,以便在任务类中实现一些强制释放资源的公共方法。我可以从 中检索对任务类的引用ScheduledExecutorService吗?或者你有什么好主意可以更好地解决我的问题?

第一个解决方案:包裹它!

创建一个 Wrapper 类ScheduledExecutorService并添加如下属性:

private IdentityHashMap<ScheduledFuture<?>, Runnable> taskList;

有了它,我们可以直接访问任何 Runnable 对象,或者通过ScheduledFuture与之相关的对象。对于包装器的实例化,我可以ScheduledExecutorServiceExecutors.newScheduledThreadPool()方法中获取并将其传递给我的包装器。

另一个解决方案:扩展它!

扩展ScheduledThreadPoolExecutor,添加 IdentityHashMap 属性并覆盖所有调度或取消作业的方法,以从 Map 中添加/删除引用。

两种解决方案的问题?

如果您的包装器或扩展类的调用者收到一个对象,则可以使用该方法SchedulerFuture<?>取消作业,绕过您的“胶囊”。SchedulerFuture<?>.cancel()使用包装器,您可以避免将SchedulerFuture<?>引用传递给调用者,但使用扩展类则不能(如果您在扩展类中创建自己的方法,您将获得与包装器相同的结果,但方式非常混乱) .

优雅的解决方案:您自己的调度程序!感谢 Kaj 指出...

  1. 扩展ScheduledThreadPoolExecutor覆盖 decorateTask()方法
  2. Runnable用一个 ScheduledFuture接口的实现来装饰
  3. 实现一种自定义cancel()方法,该方法实际上取消线程,但也操纵Runnable对象以强制释放资源。

查看我的博客文章以获取详细信息和代码示例!!!

4

1 回答 1

0

你在安排什么?任务是什么样的?我很难相信 finally 块没有被执行。我猜这是您已安排但尚未开始执行的任务正在泄漏资源(因为它们的 finally 块不会被执行)

如果 CentOS 真的没有执行这些 finally 块,这听起来像是一个非常糟糕的 VM 实现。在任何其他 VM 实现中都没有听说过这一点。

您可以做的一种选择,而不是引用所有计划任务,是子类ScheduledThreadPoolExecutor化并覆盖decorateTask方法,以便它们用您的类装饰任务,然后拦截取消调用。

于 2011-07-29T11:33:47.987 回答