关机钩子不会杀死执行者

时间:2013-07-05 02:29:52

标签: java multithreading concurrency timertask shutdown-hook

我有以下代码:

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...");
    }
}

当它运行时,我得到以下控制台输出:

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)

当我运行它时,应用程序永远不会终止。相反,每5秒钟,我看到一个新的“任务正在运行!”的打印件。我希望期望主线程到达main方法的末尾,打印“Initializing shutdown ...”,调用添加的关闭钩子,杀死执行器,最后打印出来“停机钩完了!”。

相反,“任务正在运行”只是不断打印,程序永远不会终止。这是怎么回事?

2 个答案:

答案 0 :(得分:2)

我不是专家,但AFAIK必须让所有非守护程序线程终止才能使 关闭钩子 “启动”。 在原始示例中,您有3个非守护进程:

  1. “Main”的主题 - 这是你想要的唯一非守护进程..
  2. 运行“TimerTask”的线程 - 它由“Timer”创建,你通过固定到Timer(true)
  3. 来覆盖它
  4. 运行“worker”的线程 - 它由“executor”创建,为了让“executor”创建守护进程线程,你应该创建一个 ThreadFactory 。 (至少这是我所知道的方式;可能有其他方式......)
  5. 所以我认为你应该做的是创建一个 ThreadFactory 并在初始化“executor”时使用它。

    创建一个将成为 ThreadFactory 的类:

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

    - 当然重要的一行是setDaemon:)

    将其实例作为参数传递给newCachedThreadPool方法:

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

    应用这两项更改对我来说很有把握,我得:

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

    希望它有所帮助,
    Izik

    golan2@hotmail.com

答案 1 :(得分:1)

它没有关闭,因为Timer()创建并启动一个非守护程序线程......然后它永远不会停止。

有两件事可能导致JVM自行关闭:

  • 致电System.exit()(或Runtime.halt()
  • 终止最后剩余的非守护程序线程。

由于您已经创建了第二个非守护程序线程(除了运行main()的线程外),因此将无法满足第二个条件。