在JVM关闭时触发AutoClosable

时间:2017-11-13 17:02:24

标签: java multithreading architecture jvm software-design

TL; DR : 有没有办法找出,我的代码启动的线程只能阻止JVM关闭?例如,是否可以在关机时自动触发AutoCloseable.close()?

上下文

我正在构建一个应该由多个客户使用的库。这意味着,除了提供文档之外,我无法强制执行某些操作。

建筑

我尝试将其描述为尽可能抽象并避免不必要的细节

我有一个“经理”对象(它是一种工厂),用于创建“服务”对象,而这又需要一些数据才能相应地工作。由于该数据是从某些“慢速”后端服务(也可能不时更改)加载的,因此我使用单独的(守护程序)-Thread来检查更新并尽快将新数据注入该服务。 (这也意味着除非第一次更新,否则该服务只是处于“noop模式”。但是没关系。)

现在,“更新程序”(在我的守护程序线程中运行)使用一个库,在打开连接时再次启动一个线程,并且必须调用“close”以确保此辅助线程已停止 - 否则无法实现,正确关闭JVM。

作为一个安全网,我在我的“Manager”的finalize()方法中调用了close()方法(它保留了对所有Updater实例的引用)。这不是100%安全,因为它在GC运行时是不可预测的(在关机期间甚至更多!),但这是我唯一的选择。

更新Here is some abstract example code that illustrates the architecture and the according problem

问题

这种架构会导致两个可能的陷阱:

  1. 如果实现没有保留对管理器实例的引用,那么它将在某个时刻被垃圾收集,并且通过finalize方法将停止必要的后台更新。

  2. 如果实现保留了管理器的实例,则必须在关闭系统的过程中调用close方法,否则JVM无法正常终止。

  3. 所以我的实际问题是使用该库的开发人员的“潜在不可靠性”。

    有没有人知道如何构建一个可以解决两个陷阱的解决方案? 在Shutdown期间调用一些Auto-AutoCloseable;会很好(例如DestroyJavaVM Thread或类似的东西)。

    解决方案我尝试失败

    1. 在Updater中,我正在关闭“try-finally”块中的“有问题”连接,但该守护进程线程也不会自动中断/停止。

    2. 我注册了一个会关闭所有连接的Runtime.getRuntime().addShutdownHook(...),但是这个关闭挂钩永远不会被调用,因为只有当所有用户线程都停止时才会启动关闭。

    3. 更新:解决了我的实施问题,但没有解决问题

      我解决了我的问题,因为我发现第三方库(RabbitMQ客户端)提供了一个setThreadFactory方法,我可以用它来确保生成的线程是守护程序线程。 我的第三方图书馆祝你好运,但所描述的问题仍然存在。

2 个答案:

答案 0 :(得分:0)

我希望关闭AutoCloseable资源,以便关闭是有序的,我想。

应该使用AutoCloseable对象(由您的库客户端使用),以确保它们在不再需要时关闭。几乎在所有情况下,它们都应该使用try-with-resources块,因此即使抛出异常它们也会被关闭。

您应该利用这一点,要求您的库客户端在收到关闭程序的请求时对每个线程执行受控关闭。线程通过从每个Runnable.run方法返回或从每个Runnable.run方法抛出异常来执行受控关闭。我相信这是关闭资源的唯一可靠方法,因为它确保以正确的顺序重新分配嵌套资源分配。更一般地说,作为库编写者,您无法知道库客户端在关闭时可能要执行的其他操作,因此您应该让他们完全控制关闭。

你可以通过让你的库代码正确处理InterruptedException和Thread.interrupted标志来帮助他们做到这一点。

答案 1 :(得分:0)

好吧,我猜这个问题没有好的解决方案,但是因为我发现我的第三方库提供了创建守护进程线程的可能性,这正是解决它的必要条件。

也许这也是一个应该在“人类层面”解决的问题,它提供了一个好的文档并确保正确使用AutoCloseable。一个优秀的开发人员现在应该如何处理。

从技术角度来看,我发现了这些可能的解决方案,这些解决方案只是“安全网”,没有人应该依赖。

  • 在finalize方法中调用“close()”
  • 我实现了一项服务,可用于注册AutoClosable资源。它在Daemon-Thread内部运行并每隔几秒检查一次,如果它找到了JavaDestroyVM线程,在这种情况下,关闭所有已注册的AutoClosable并自行停止。
    披露:如果系统在“主方法之外”运行(JavaDestroyVM线程将一直运行),这个解决方案将无效。

更新:RegisterAutoClosable-Service是一个非常丑陋/ hacky的解决方案 - 我删除了它并计划更改设计,以避免这种情况,但最后它是实施开发人员关闭的责任正确地开放了资源。

相关问题