我在JEE环境中获得了ScheduledExecutorService
任务调度。其中一些任务是在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代码被中断或终止,最后 即使作为一个整体的应用程序,块也可能无法执行 继续进行。
所以,我需要的是对所有计划任务的引用,以便在Task类中实现一些强制释放资源的公共方法。我可以从ScheduledExecutorService
检索对任务类的引用吗?或者你有一个很好的想法,以更好的方式解决我的问题?
第一个解决方案:包裹它!
为ScheduledExecutorService
创建一个Wrapper类,并添加如下属性:
private IdentityHashMap<ScheduledFuture<?>, Runnable> taskList;
有了它,我们可以直接访问任何Runnable对象,或者通过与它相关的ScheduledFuture
访问。对于包装器的实例化,我可以从ScheduledExecutorService
方法获取Executors.newScheduledThreadPool()
并将其传递给我的包装器。
另一种解决方案:扩展它!
扩展ScheduledThreadPoolExecutor
,添加IdentityHashMap属性并覆盖调度或取消作业的所有方法,以添加/删除Map中的引用。
这两个解决方案存在问题?
如果包装器或扩展类的调用者收到SchedulerFuture<?>
对象,则可以使用SchedulerFuture<?>.cancel()
方法取消作业,绕过“胶囊”。使用包装器可以避免将SchedulerFuture<?>
引用传递给调用者,但是使用扩展类不能(如果在扩展类中创建自己的方法,则会得到与包装器相同的结果,但是一种非常令人困惑的方式)。
优雅的解决方案:您自己的调度程序!感谢Kaj指出它......
ScheduledThreadPoolExecutor
以覆盖。{
decorateTask()
方法Runnable
ScheduledFuture
界面cancel()
方法
取消线程但也操纵Runnable
对象强制
资源释放。查看我的博客post了解详情和代码示例!!!
答案 0 :(得分:0)
你在安排什么?这些任务是什么样的?我发现很难相信finally块没有被执行。我猜这是你已经安排的任务,但是没有开始执行那些泄漏资源(因为他们的finally块不会被执行)
如果真的没有执行那些最终的块,那么在CentOS上听起来就像是一个非常糟糕的虚拟机实现。在任何其他VM实现中都没有听说过。
您可以执行的一个选项(而不是引用所有计划任务)是子类ScheduledThreadPoolExecutor
并覆盖decorateTask
方法,以便它们用您的类装饰任务,然后拦截取消调用。