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 秒ごとに「Task is running!」という新しい println が表示されます。メイン スレッドがメソッドの最後に到達し、「Initializing shutdown...」を出力し、追加されたシャットダウン フックを呼び出し、executor を強制終了し、最後に「Shutdown hook is finished!」を出力すると予想していました。main

代わりに、「タスクは実行中です」というメッセージが表示され続け、プログラムが終了することはありません。何が起きてる?

4

2 に答える 2

2

私は専門家ではありませんが、知る限り、シャットダウン フックを「開始」するには、すべての非デーモン スレッドを終了する必要があります。元の例では、3 つの非デーモンがあります。

  1. 「メイン」のスレッド – これは、ここで必要な唯一の非デーモンです..
  2. 「TimerTask」を実行するスレッド – 「Timer」によって作成され、修正してカバーしましたTimer(true)
  3. 「ワーカー」を実行するスレッド – 「エグゼキューター」によって作成されます。「エグゼキューター」がデーモン スレッドを作成するには、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());

これらの2つの変更を適用すると、うまくいきました。

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 に答える