我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
与之相关的对象。对于包装器的实例化,我可以ScheduledExecutorService
从Executors.newScheduledThreadPool()
方法中获取并将其传递给我的包装器。
另一个解决方案:扩展它!
扩展ScheduledThreadPoolExecutor
,添加 IdentityHashMap 属性并覆盖所有调度或取消作业的方法,以从 Map 中添加/删除引用。
两种解决方案的问题?
如果您的包装器或扩展类的调用者收到一个对象,则可以使用该方法SchedulerFuture<?>
取消作业,绕过您的“胶囊”。SchedulerFuture<?>.cancel()
使用包装器,您可以避免将SchedulerFuture<?>
引用传递给调用者,但使用扩展类则不能(如果您在扩展类中创建自己的方法,您将获得与包装器相同的结果,但方式非常混乱) .
优雅的解决方案:您自己的调度程序!感谢 Kaj 指出...
- 扩展
ScheduledThreadPoolExecutor
覆盖decorateTask()
方法 Runnable
用一个ScheduledFuture
接口的实现来装饰- 实现一种自定义
cancel()
方法,该方法实际上取消线程,但也操纵Runnable
对象以强制释放资源。
查看我的博客文章以获取详细信息和代码示例!!!