简体   繁体   English

关机挂钩不会杀死执行程序

[英]Shutdown hook is not killing executor

I have the following code: 我有以下代码:

public class Driver {
    private ExecutorService executor = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        Driver d = new Driver();
        d.run();
    }

    private void run() {
        final Timer timer = new Timer();
        final TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("Task is running!");
            }
        };

        Runnable worker = new Runnable() {
            @Override
            public void run() {
                timer.scheduleAtFixedRate(task, new Date(), 5 * 1000);
            }
        };

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("Shutdown hook is being invoked!");

                try {
                    if(executor.awaitTermination(20, TimeUnit.SECONDS))
                        System.out.println("All workers shutdown properly.");
                    else {
                        System.out.println(String.format("Maximum time limit of %s reached " +
                                "when trying to shut down workers. Forcing shutdown.", 20));
                        executor.shutdownNow();
                    }
                } catch (InterruptedException interrupt) {
                    System.out.println("Shutdown hook interrupted by exception: " +
                            interrupt.getMessage());
                }

                System.out.println("Shutdown hook is finished!");
            }
        });

        executor.submit(worker);

        System.out.println("Initializing shutdown...");
    }
}

When this runs I get the following console output: 当运行时,我得到以下控制台输出:

Initializing shutdown...
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
... (this keeps going non-stop)

When I run this, the application never terminates. 当我运行此程序时,应用程序永不终止。 Instead, every 5 seconds, I see a new println of "Task is running!". 相反,每隔5秒,我会看到一个新的println“任务正在运行!”。 I would have expected the main thread to reach the end of the main method, print "Initializing shutdown...", invoked the added shutdown hook, killed the executor, and finally print out "Shutdown hook is finished!". 我本来希望主线程到达main方法的末尾,打印“ Initializing shutdown ...”,调用添加的shutdown钩子,杀死执行程序,最后打印出“ Shutdown钩子完成!”。

Instead, "Task is running" just keeps getting printed and the program never terminates. 相反,“任务正在运行”只会不断打印,程序永远不会终止。 What's going on here? 这里发生了什么?

I am no expert but AFAIK you must have all non-Daemon threads terminated in order for the shutdown hook to “kick in”. 我不是专家,但是AFAIK您必须终止所有非守护进程线程,才能使关闭挂接 “插入”。 In the original example you have 3 non-Daemon: 在原始示例中,您有3个非守护进程:

  1. The thread of “Main” – this is the only non-Daemon you want here.. “ Main”线程–这是您想要的唯一非守护程序。
  2. The thread that runs the “TimerTask” – it is created by the “Timer” and you covered it by fixing to Timer(true) 运行“ TimerTask”的线程–由“ Timer”创建,并且您通过固定为Timer(true)覆盖
  3. The thread that runs the “worker” – it is created by the “executor” and in order for the “executor” to create Daemon threads you should create a ThreadFactory . 运行“工作者”的线程–它是由“执行者”创建的,并且为了使“执行者”创建守护程序线程,您应该创建一个ThreadFactory (at least this is the way I know; there might be other ways...) (至少这是我所知道的方式;可能还有其他方式...)

So I think what you should do is to create a ThreadFactory and use it when initializing the “executor”. 因此,我认为您应该做的是创建一个ThreadFactory并在初始化“执行程序”时使用它。

Create a class that will be the ThreadFactory : 创建一个将是ThreadFactory的类

private class WorkerThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, "Worker");
        t.setDaemon(true);
        return t;
    }
}

-- the important line is the setDaemon of course :) -当然重要的是setDaemon :)

Pass an instance of it as a parameter to the newCachedThreadPool method: 将其实例作为参数传递给newCachedThreadPool方法:

private ExecutorService executor = Executors.newCachedThreadPool(new WorkerThreadFactory());

Applying these 2 changes did the trick for me and I got to: 应用这2个更改对我来说很成功,所以我做到了:

Maximum time limit of 20 reached when trying to shut down workers. Forcing shutdown.
Shutdown hook is finished!

Hope it helps, 希望能帮助到你,
Izik 伊兹克

golan2@hotmail.com golan2@hotmail.com

It is not shutting down because Timer() creates and starts a non-daemon thread ... which is then never stopped. 它没有关闭,因为Timer()创建并启动了一个非守护线程...然后永不停止。

There are two things that can cause the JVM to shutdown of its own accord: 有两种情况可以导致JVM自行关闭:

  • A call to System.exit() (or Runtime.halt() ) 调用System.exit() (或Runtime.halt()
  • The termination of the last remaining non-daemon thread. 最后剩余的非守护线程的终止。

Since you have created a second non-daemon thread (in addition to the thread that is running main() ) the second condition won't be met. 由于您创建了第二个非守护进程线程(除了运行main()的线程之外),因此将不满足第二个条件。

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

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