Java JVM关闭时触发自动关闭

Java JVM关闭时触发自动关闭,java,multithreading,architecture,jvm,software-design,Java,Multithreading,Architecture,Jvm,Software Design,TL;博士: 有没有办法发现,JVM关闭只在我的代码启动的线程中被阻止?例如,是否可以在关机时自动触发AutoCloseable.close() 上下文 我正在建一个图书馆,应该有几个客户使用。这意味着,除了提供文档外,我不能强制执行某些事情 建筑学 (我尽量抽象地描述它,避免不必要的细节) 我有一个“Manager”对象(类似于工厂),用于创建一个“Service”对象,它反过来需要一些数据来相应地工作。由于数据是从某个“慢”后端服务加载的(也可能会不时更改),因此我使用一个单独的(守护进程)

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

上下文 我正在建一个图书馆,应该有几个客户使用。这意味着,除了提供文档外,我不能强制执行某些事情

建筑学 (我尽量抽象地描述它,避免不必要的细节)

我有一个“Manager”对象(类似于工厂),用于创建一个“Service”对象,它反过来需要一些数据来相应地工作。由于数据是从某个“慢”后端服务加载的(也可能会不时更改),因此我使用一个单独的(守护进程)线程来检查更新,并在可用时将新数据注入该服务。(这也意味着,除非第一次更新,否则该服务只是处于“noop模式”。但这没关系。)

现在,“更新程序”(在我的守护进程线程中运行)使用一个库,该库在打开连接时再次启动一个线程,并且有必要调用“close”以确保该辅助线程停止,否则就不可能正确关闭JVM

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

更新

问题 此体系结构可能导致两个陷阱:

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

  • 如果实现保留了管理器的一个实例,那么它必须在相应系统关闭期间调用close方法,否则JVM无法正确终止

  • 因此,我的实际问题是使用该库的开发人员的“潜在不可靠性”

    有没有人知道如何构建一个解决方案来处理这两个陷阱? 如果有一些自动关闭的,那就太好了;)在关机期间调用(例如,由DestroyJavaVM线程或类似线程调用)

    我尝试的解决方案没有成功
  • 在更新程序中,我关闭了“try finally”块中的“有问题”连接,但是守护进程线程也不会自动中断/停止

  • 我注册了一个
    Runtime.getRuntime().addShutdownHook(…)
    ,它将关闭所有连接,但从未调用此关闭挂钩,因为只有在所有用户线程停止时才会启动关闭

  • 更新:在我的实现中解决了,但不是问题 我解决了我的问题,因为我发现第三方库(RabbitMQ客户端)提供了一个
    setThreadFactory
    方法,我可以使用该方法确保生成的线程是守护进程线程。
    祝我的第三方库好运,但描述的问题仍然可能出现。

    我想,您希望关闭自动关闭的资源,以便有序关闭

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

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


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

    好的,我想对于这个问题没有好的解决方案,但是因为我发现我的第三方库提供了创建守护进程线程的可能性,这正是修复它所必需的

    也许这也是一个问题,应该通过提供良好的文档并确保正确使用AutoCloseable在“人的层面”上解决。一个好的开发人员应该知道如何处理这个问题

    从技术角度看,我找到了这些可能的解决方案,它们只是任何人都不应该依赖的“安全网”

    • 在finalize方法内调用“close()”
    • 我实现了一个服务,可以用来注册自动关闭的资源。它在守护进程线程内运行,每隔几秒钟检查一次是否找到JavaDestroyVM线程,在这种情况下,关闭所有已注册的AutoClosable并自行停止。
      披露:如果系统“在主方法之外”运行(JavaDestroyVM线程将一直运行),则此解决方案将不起作用。

    更新:RegisterAutoClosable服务是一个非常丑陋/有黑客行为的解决方案-我删除了它并计划更改设计,以避免这种情况,但最终实现开发人员有责任正确关闭打开的资源。

    你的第一句话是误导。据我所知,您所说的是当不存在活动的非守护进程线程时发生的自动关闭。然后,您的问题不是“在JVM终止时强制停止用户线程(daemon=false)”,因为当用户线程尚未停止时,不会发生JVM终止。所以第一个问题是,什么会触发你的清理?你的经理不会收垃圾袋的