【发布时间】:2018-04-26 10:51:43
【问题描述】:
TL;DR: 有没有办法找出,JVM-shutdown 只被我的代码启动的线程阻止?例如是否可以在关机时自动触发 AutoCloseable.close()?
上下文
我正在构建一个库,应该由多个客户使用。这意味着,除了提供文件之外,我不能强制执行某些事情。
架构
(我尽量把它描述得抽象一些,避免不必要的细节)
我有一个“管理器”对象(有点像工厂),用于创建一个“服务”对象,而该对象又需要一些数据来相应地工作。由于该数据是从一些“慢”后端服务加载的(也可能会不时更改),因此我使用一个单独的(守护进程)线程来检查更新并尽快将新数据注入该服务。 (这也意味着除非第一次更新,否则该服务只是处于“noop 模式”。但这没关系。)
现在“更新程序”(在我的守护线程中运行)使用了一个库,该库在打开连接时再次启动一个线程,并且有必要调用“关闭”以确保该辅助线程停止 - 否则不可能, 以正确关闭 JVM。
作为安全网,我在“Manager”的 finalize() 方法中调用 close() 方法(它保留对所有 Updater 实例的引用)。这不是 100% 安全的,因为它在 GC 运行时是不可预测的(在关机期间更是如此!),但这是我唯一的选择。
更新:Here is some abstract example code that illustrates the architecture and the according problem
问题
这种架构会导致两个可能的缺陷:
如果实现不保留对管理器实例的引用,它将在某个时候被垃圾收集,并通过 finalize 方法停止必要的后台更新。
如果实现保留了管理器的实例,则必须在相应系统关闭期间调用close方法,否则JVM无法正常终止。
所以我的实际问题是使用该库的开发人员的“潜在不可靠性”。
有没有人知道如何构建一个可以处理这两个陷阱的解决方案? 最好有一些 Auto-AutoCloseable ;) 在关机期间调用(例如由 DestroyJavaVM 线程或类似线程)。
我尝试失败的解决方案
在更新程序中,我正在关闭“try-finally”块内的“有问题”连接,但该守护线程也不会自动中断/停止。
我注册了一个
Runtime.getRuntime().addShutdownHook(...),它会关闭所有连接,但是这个关闭钩子永远不会被调用,因为只有在所有用户线程停止时才会启动关闭。
更新:在我的实施中解决了,但不是问题
我解决了我的问题,因为我发现第三方库(RabbitMQ 客户端)提供了一个 setThreadFactory 方法,我可以使用它来确保生成的线程是守护线程。
祝我的第 3 方库好运,但所描述的问题仍然可能发生。
【问题讨论】:
-
你的第一句话是误导。据我了解,您说的是在不存在活动的非守护线程时发生的自动关闭。然后,您的问题是 not “强制停止用户线程 (daemon=false) on JVM 终止”,因为当用户线程没有发生 JVM 终止时还没有停止。所以第一个问题是,what 应该触发你的清理工作?只要线程处于活动状态,您的管理器就不会收集垃圾,但是当它们不活动时,您不需要进行此清理(那时,自动关闭将起作用)。
-
你说得对,这正是我的困境。实际上,我想停止由在守护线程内运行的代码间接打开的用户线程。我会尝试用不同的方式表达。
标签: java multithreading architecture jvm software-design