web-dev-qa-db-ja.com

JVMはデーモンスレッドをどのように終了しますか?または正常に終了するデーモンスレッドを書く方法

架空のシナリオ:
I/Oを担当するデーモンスレッドがあり、メインスレッドが終了して戻り、JVMがデーモンスレッドを終了することにしました。

それはどのように行うのですか?割り込み?確定しますか?デーモンスレッドをコーディングして、終了時に適切に反応するようにするにはどうすればよいですか?

28
Aaron J Lang

私はテストとして次のコードを書いたところです:

public class DaemonThreadPlay {
    public static void main(String [] args) {
        Thread daemonThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        System.out.println("Try block executed");
                        Thread.sleep(1000l);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            }

            @Override
            public void finalize() {
                System.out.println("Finalize method called");
            }
        };
        daemonThread.setDaemon(true);
        daemonThread.start();

        try {
            Thread.sleep(2500l);
        } catch (Throwable t) {
            //NO-OP
        }
    }
}    

デーモンスレッドのcatchブロックとfinalizeメソッドにブレークポイントを設定します。 tryブロックが実行されたにもかかわらず、どちらのブレークポイントにも到達しませんでした。このコードには明らかに同期/タイミングの問題がありますが、シャットダウン時にデーモンスレッドが中断されたり、finalize()メソッドが必ずしも呼び出されたりすることはないと安全に結論付けることができると思います。

いつでもシャットダウンフックをJVMランタイムに追加できます。

Thread shutdownHook = ... // construct thread that somehow
                          // knows about all the daemon threads
Runtime.getRuntime().addShutdownHook(shutdownHook);

シャットダウンフックは、「グレースフル」シャットダウンに必要なすべてのタスクを実行できます。

11
skiller3

デーモンスレッドとは何かを誤解していると思います。

参照 Javaのデーモンスレッドとは

要約すると、それは基本的にデーモンスレッドがI/Oを実行したり、リソースを保持したりしてはならないことを意味します。この基本的なルールに違反している場合、そのスレッドはデーモンスレッドとしての資格がありません。

シャットダウンフックの追加は、JVMの終了前にコードが呼び出されるようにするための標準的な方法ですが、これが100%保証されるわけではありません。たとえば、JVMがクラッシュし、OSを保護する方法でOSがリソースを整理する可能性があります、ただし、アプリケーションが一貫性のない/誤った状態のままになる可能性が非常に高くなります。

システムのチェックポイントと回復のメカニズムは、ソフトウェアの初期(オペレーティングシステムやバッチ操作など)まで遡ります。残念ながら、この問題に対処する「銀の弾丸」アプローチ(API)がないため、このホイールは再発明され続けています。十分に一般的な方法。

5
user924272

AFAIK、Daemonスレッドは、メインストリームのI/O作業には向いていません。すべてのスレッドが完了すると、JVMはすべてのデーモンスレッドを突然閉じる場合があります。要件に対する可能な回避策は、以下のようなExecutorServiceを作成することです。

ExecutorService execPool = Executors.newSingleThreadExecutor(new ThreadFactory() {

    @Override    
    public Thread newThread(Runnable runnable) {       
         Thread thread = Executors.defaultThreadFactory().newThread(runnable);
         thread.setDaemon(true);
         return thread;    
    } 
}); 

シャットダウンフックからexecutorserviceシャットダウンメソッドを呼び出します。

Runtime.getRuntime().addShutdownHook(....)
4
kosa

割り込みと結合を使用します。

class Daemon extends Thread {
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println(e);
                break;
            }
        }
        System.out.println("exit run()");
    }
}   
public class So8663107 {
    public static void main(String[] arguments) throws InterruptedException {
        System.out.println(Thread.activeCount());
        Daemon daemon = new Daemon();
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(2500);
        System.out.println(Thread.activeCount());
        daemon.interrupt();
        daemon.join();
        System.out.println(Thread.activeCount());
    }
}
1
Ray Tayek