Java Shutdown挂钩未运行

时间:2012-09-13 10:58:03

标签: java multithreading

我是Java / threads的新手,我继承了类似下面的代码。它是一个命令行程序,main()只启动5-6种不同类型的线程,并以^ C退出。我想添加一个关闭钩子来正确关闭所有线程并按以下方式调整它。

我在所有线程中添加了Shutdown钩子和stopThread()方法(比如MyWorker类中的那个)

问题是当我按下^ C时,我没有看到Thread的run方法中的结束消息。这是在后台完成还是我的方法有问题。另外,我应该遵循更好的模式吗?

由于

 public class Main {
     public static MyWorker worker1 = new MyWorker();
     // .. various other threads here

     public static void startThreads() {
         worker1.start();
         // .. start other threads
     }

     public static void stopThreads() {
         worker1.stopThread();
         // .. stop other threads
     }

     public static void main(String[] args)
             throws Exception {

         startThreads();

         // TODO this needs more work (later)

         Runtime.getRuntime().addShutdownHook(new Thread() {
             @Override
             public void run() {
                 try {
                     stopThreads();
                 } catch (Exception exp) {

                 }
             }
         });
     } }

 public class MyWorker extends Thread {
     private volatile boolean stop = false;

     public void stopThread() {
         stop = true;
     }

     public void run() {
         while (!stop) {
             // Do stuff here
         }
         // Print exit message with logger
     } 
}

5 个答案:

答案 0 :(得分:7)

当您调用System.exit()或通过信号终止时,它会停止所有现有线程并启动所有关闭挂钩。也就是说,当你开始挂钩时,你所有的线程都可能已经死了。

您应该确保干净地关闭资源,而不是试图干净地停止线程。

答案 1 :(得分:6)

在某些情况下可能无法执行关机挂钩!

首先要记住的是,无法保证关闭挂钩始终会运行。如果JVM由于某些内部错误而崩溃,那么它可能会在没有机会执行单个指令的情况下崩溃。此外,如果O / S给出SIGKILL(http://en.wikipedia.org/wiki/SIGKILL)信号(Unix / Linux中的kill -9)或TerminateProcess(Windows),则应用程序需要立即终止,而不必等待任何清理活动。除了上述内容之外,还可以通过调用Runime.halt()方法来终止JVM而不允许关闭挂钩运行。

当应用程序正常终止时(当所有线程完成或调用System.exit(0)时)将调用关闭挂钩。此外,当JVM由于外部原因(例如用户请求终止(Ctrl + C))而关闭时,由O / S(正常kill命令,不带-9)或操作系统关闭时发出SIGTERM

答案 2 :(得分:5)

我猜您可以将代码转移到ExectuterService

private final ExecutorService pool;
pool = Executors.newFixedThreadPool(poolSize);
pool.execute(Instance of Runnable);
pool.shutdown(); 

ExectuterService.shutdown

  

启动有序关闭,其中先前提交的任务已执行,但不会接受任何新任务。如果已经关闭,调用没有其他影响。

答案 3 :(得分:1)

尝试将您的线程作为守护程序线程。

添加构造函数

public MyWorker(boolean isDaemon) {
this.setDaemon(true);
}

或在调用start之前设置为守护进程。

worker1.setDaemon(true);
worker1.start();

按Ctrl C并退出时,线程将停止。

答案 4 :(得分:0)

这里发生的是您调用stopThread()方法,但是在终止之前不要等待线程实际完成。

如果在停止JVM之前在所有线程上调用join(),您可能会看到“停止日志”。

public static void stopThreads() {
     worker1.stopThread();
     // .. stop other threads

    for(Thread t: workers) {
       t.join();
    }
 }