【问题标题】:java thread stopped during OS initiated shutdown (contradicts JAVA docs!)java 线程在操作系统启动关闭期间停止(与 JAVA 文档相矛盾!)
【发布时间】:2014-08-27 19:17:48
【问题描述】:

java.lang.Thread.setDaemon(boolean)

当唯一运行的线程都是守护线程时,Java 虚拟机退出。

然而,在下面的代码中,“安全关闭”在中断(操作系统风格)进程时永远不会发生 不,我没有使用 SIGKILL...

由于文档错误 (?) 是我唯一的办法来跟踪所有非守护线程并在关闭挂钩中加入它们吗?

public class Main {
  public static void main(String... args) {
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        System.out.println("shutdown hook activated");
      }
    });
    new Thread(new Runnable() {
      public void run() {
        while (true) {
          try {
            System.out.println("sleeping for 1000 seconds!");
            Thread.sleep(1000000);
          } catch (InterruptedException e) {
            System.out.println("INTERRUPTED");
            break;
          }
        }
        System.out.println("SAFELY SHUTTING DOWN");
      }
    }).start();
  }
}

【问题讨论】:

  • 文档没有错。从逻辑上讲,“当唯一运行的线程都是守护线程时,Java 虚拟机退出”确实暗示它在其他情况下也不会关闭。
  • 文档的含义已经解释过了,所以你的例子与文档并不矛盾。
  • "一旦关机程序开始,它只能通过调用停止方法来停止,该方法会强制终止虚拟机。"关闭钩子文档非常清楚您不能使用它来停止关闭这一事实(如果您阅读文档的其余部分,您会看到漏洞,但是非常脆弱)
  • Oracle documentation 同时提到了SIGINTabrupt termination。您还知道关闭挂钩可能永远不会被调用吗?
  • @user3338098 你没有得到“与文档所说的相反”。正如我所说,您引用的文档并没有说明或暗示您要解决的问题。你在不合逻辑地解释它。具体来说,您是在否认前件。 en.wikipedia.org/wiki/Denying_the_antecedent

标签: java multithreading interrupt shutdown-hook interrupted-exception


【解决方案1】:

注意Runtime#addShutdownHook(Thread) 的javadoc。

Java 虚拟机响应两种情况而关闭 事件:

  • 程序正常退出,当最后一个非守护线程退出时或调用退出(相当于 System.exit)方法时,或
  • 虚拟机响应用户中断而终止,例如键入^C,或系统范围的事件,例如用户注销或 系统关闭。

SIGINT 是用户中断,相当于命令行中的^C

此 javadoc 说明了关闭挂钩在这些条件下的行为方式。

您引用的 javadoc 解释了 JVM 在守护线程上下文中的行为。

它们不是相互排斥的。此外,没有任何迹象表明您正在运行的线程会被中断。

【讨论】:

    【解决方案2】:

    我认为问题在于您的关闭挂钩不完整。钩子需要等到“安全关闭”操作完成后才返回。

    这是您的代码的修改版本。

    public static void main(String... args)  {
    
        final AtomicBoolean shouldBeRunning = new AtomicBoolean(true);
        final AtomicBoolean isRunning = new AtomicBoolean(false);
    
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                shouldBeRunning.set(false);
                System.out.println("shutdown hook activated");
                while(isRunning.get()) {
                    try {
                        System.out.println("waiting on safe shutdown to complete");
                        Thread.sleep(250);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        new Thread(new Runnable() {
            public void run() {
                isRunning.set(true);
                while (shouldBeRunning.get()) {
                    try {
                        System.out.println("sleeping for 1 seconds!");
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println("INTERRUPTED");
                        break;
                    }
                }
                System.out.println("SAFELY SHUTTING DOWN");
                isRunning.set(false);
            }
        }).start();
    }
    
    public static void main(String... args) throws InterruptedException {
    
        final AtomicBoolean shouldBeRunning = new AtomicBoolean(true);
        final AtomicBoolean isRunning = new AtomicBoolean(false);
    
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                shouldBeRunning.set(false);
                System.out.println("shutdown hook activated");
                while(isRunning.get()) {
                    try {
                        System.out.println("waiting on safe shutdown to complete");
                        Thread.sleep(250);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        new Thread(new Runnable() {
            public void run() {
                isRunning.set(true);
                while (shouldBeRunning.get()) {
                    try {
                        System.out.println("sleeping for 1 second!");
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println("INTERRUPTED");
                        break;
                    }
                }
                System.out.println("SAFELY SHUTTING DOWN");
                isRunning.set(false);
            }
        }).start();
    }
    

    输出是:

    sleeping for 1 second!
    sleeping for 1 second!
    shutdown hook activated
    waiting on safe shutdown to complete
    waiting on safe shutdown to complete
    SAFELY SHUTTING DOWN
    

    跟踪所有非守护线程并在关闭挂钩中加入它们不会让您阻止程序被终止,因为关闭挂钩有时间限制。当这个时间到期时,即使钩子没有完成,JVM也会退出。

    【讨论】:

      猜你喜欢
      • 2018-07-22
      • 2011-05-24
      • 1970-01-01
      • 1970-01-01
      • 2011-05-02
      • 2020-02-20
      • 1970-01-01
      • 2020-05-29
      • 2017-03-09
      相关资源
      最近更新 更多