繁体   English   中英

Java关闭挂钩中的死锁

[英]Deadlock in Java shutdown hook

System.exit()将突然退出JVM,并且不会正常关闭。 但是System.exit()具有用于正常关闭的挂钩。 但是它陷入僵局..

class ExitPuzzle{
    private static final Object lock = new Object();

    public static void main(String... args) {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Locking");
                synchronized (lock) {
                    System.out.println("Locked");
                }
            }
        }));
        synchronized (lock) {
            System.out.println("Exiting");
            System.exit(0);
        }
    }
}

输出为::

       Exiting
       Locking

问题是为什么System.exit(0)时JVM无法关闭? 被执行? 为什么会陷入僵局? 开发人员在代码中使用ShutDowmHook时是否需要小心,还是应该不允许编写死锁代码?

该程序处于死锁状态,因为两个线程正在请求相同的锁,而持有该锁的线程永不松手。 在上面的简单示例中,根本不需要锁定。

最初可能不清楚这里有多个线程,所以要确认这是Runtime.addShutdownHook文档中的摘录

关闭钩子只是一个已初始化但未启动的线程。 当虚拟机开始其关闭序列时,它将以未指定的顺序启动所有已注册的关闭挂钩,并使其同时运行。

另一个可能不清楚的方面是,由于死锁,对System.exit(0)的调用不会退出。 这是因为System.exit(0)阻塞,直到关闭线程全部完成为止。 可以通过阅读下面来自ApplicationShutdownHooks.runHooks的代码来确认这一点,并在System.exit(0)中稍作调用。 我在评论中强调了两条关键线。 1)启动新线程,以及2)阻塞直到它们完成。 并且如上所述,该join()将不会返回,因为在AFTER join()返回之前,注册的关闭挂钩所需的锁定不会被释放。 这种循环情况是死锁的定义,A直到B完成才可以继续,而B直到A完成才可以继续。 因此无法取得进展。

static void runHooks() {
    Collection<Thread> threads;
    synchronized(ApplicationShutdownHooks.class) {
        threads = hooks.keySet();
        hooks = null;
    }

    for (Thread hook : threads) {
        hook.start();                    // STARTS THE EXTRA THREADS
    }
    for (Thread hook : threads) {
        try {
            hook.join();                 // WAITS FOR THE EXTRA THREADS TO FINISH
        } catch (InterruptedException x) { }
    }
}

Runtime.addShutdownHook上的javadoc对此有很多详细信息:

关机挂钩在虚拟机的生命周期中的某个微妙时刻运行,因此应进行防御性编码。 尤其应将其编写为线程安全的,并尽可能避免死锁。 他们也不应盲目依赖可能已经注册了自己的关闭钩子的服务,因此自己可能正在关闭过程中。 尝试使用其他基于线程的服务(例如AWT事件调度线程)可能会导致死锁。

Runtime.getRuntime().halt(0) 

戕延迟计时器是用于避免死锁按照另一替代文章。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM