4

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

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

问题是当我按下 ^CI 时,看不到来自 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
     } 
}
4

5 回答 5

10

在某些情况下可能不会执行 Shutdown Hooks!

首先要记住的是,不能保证关闭挂钩始终运行。如果 JVM 由于某些内部错误而崩溃,那么它可能会崩溃而没有机会执行一条指令。

此外,如果操作系统发出SIGKILL ( http://en.wikipedia.org/wiki/SIGKILL ) 信号(kill -9在 Unix/Linux 中)或 TerminateProcess (Windows),则应用程序需要立即终止,甚至无需等待任何清理活动。除了上述之外,还可以通过调用Runime.halt()方法来终止JVM而不让shutdown hooks运行。

Shutdown hooks are called when the application terminates normally (when all threads finish, or when System.exit(0) is called). Also, when the JVM is shutting down due to external causes such as user requesting a termination (Ctrl+C), a SIGTERM being issued by O/S (normal kill command, without -9), or when the operating system is shutting down.

于 2016-01-04T07:38:08.640 回答
7

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

与其尝试干净地停止线程,不如确保干净地关闭资源。

于 2012-09-13T11:00:34.830 回答
5

我想您可以将代码转移到ExecutorService

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

ExecutorService.shutdown

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

于 2012-09-13T11:31:31.367 回答
2

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

添加构造函数

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

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

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

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

于 2012-09-13T11:00:42.880 回答
0

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

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

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

    for(Thread t: workers) {
       t.join();
    }
 }
于 2012-09-13T11:26:48.840 回答