0

我有以下代码:

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 秒,我就会看到一个新的“任务正在运行!”的 println。我本来希望主线程到达main方法的末尾,打印“正在初始化关闭...”,调用添加的关闭挂钩,杀死执行程序,最后打印出“关闭挂钩完成!”。

相反,“任务正在运行”只是不断打印,程序永远不会终止。这里发生了什么?

4

2 回答 2

2

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

  1. “Main”的线程——这是你想要的唯一非守护进程..
  2. 运行“TimerTask”的线程——它是由“Timer”创建的,你通过修复来覆盖它Timer(true)
  3. 运行“worker”的线程——它是由“executor”创建的,为了让“executor”创建守护线程,你应该创建一个ThreadFactory。(至少这是我知道的方式;可能还有其他方式......)

所以我认为你应该做的是创建一个ThreadFactory并在初始化“执行器”时使用它。

创建一个将成为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!

希望它有帮助,
伊兹克

golan2@hotmail.com

于 2013-07-07T21:26:06.647 回答
1

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

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

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

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

于 2013-07-05T02:46:20.580 回答