集合未在 java 关闭挂钩中迭代

Collection not being iterated in a java shutdown hook

我已经为那个荒谬的问题苦苦挣扎了几个小时,所以现在我正在寻求帮助。

1 班轮:我的关闭钩子显然在完成任务之前就终止了。

我 运行ning 的代码如下所示:

class Test {

    static {
        Runtime.getRuntime().addShutdownHook(new Thread(Test::shutdown));
    }

    // more methods
    private static void shutdown() {
        Collection<Foo> coll = some.instance.ofHashMap.values();
        System.out.println("collSize=" + coll.size());
        for (Foo o : coll) {
            System.out.println("Calling bar on foo");
            o.bar();
        }
        System.out.println("End of hook");
    }
}

但输出是:

collSize=1

如果我 运行 带有 -server 选项的 jvm,我可能会很幸运并且 "Calling bar on foo" 打印但它仍然不打印 "End of hook".

不幸的是,我无法创建一个简短的可执行示例来说明问题。我有一个,但它显示一切正常,并且集合按预期迭代。 上面的代码是我正在处理的一个更大的程序的摘录,但是我的关闭是钩子只是做了上面的事情(获取一个非空集合并迭代)。

对可能发生的事情有什么想法吗?我完全迷失在这里...

备注: - 代码编写、编译和 运行 for/with Java 8u45 - 我用 Ctrl+C 终止程序,结果,JVM 存在代码 130

来自 the docs(强调我的)您只承诺“尽最大努力”关闭挂钩:

Shutdown hooks run at a delicate time in the life cycle of a virtual machine and should therefore be coded defensively. They should, in particular, be written to be thread-safe and to avoid deadlocks insofar as possible. They should also not rely blindly upon services that may have registered their own shutdown hooks and therefore may themselves in the process of shutting down. Attempts to use other thread-based services such as the AWT event-dispatch thread, for example, may lead to deadlocks.

Shutdown hooks should also finish their work quickly. When a program invokes exit the expectation is that the virtual machine will promptly shut down and exit. When the virtual machine is terminated due to user logoff or system shutdown the underlying operating system may only allow a fixed amount of time in which to shut down and exit. It is therefore inadvisable to attempt any user interaction or to perform a long-running computation in a shutdown hook.

所以,基本上如果有其他地方可以做,就在那里做。如果必须在关闭挂钩中执行此操作,请快点。

结果:

  • 主要是 IO 问题:与上面的示例不同,我使用 log4j2 中的记录器来打印信息。 log4j2 有自己的 shutdownHook,它比我的关闭挂钩更快地杀死所有记录器,因为关闭挂钩是在 JVM 中并行执行的。在 disabling log4j2 shutdownHook 之后,一切似乎都按预期工作。
  • 钩子总是被完全执行(通过将调试器附加到 jvm 很容易证明)
  • 在我的特殊情况下,我忘记关闭+等待我的线程池来完成我想要的所有清理工作
  • 我应该在发帖之前睡过头了:/

感谢大家的快速回复和帮助。