なぜcatch InterruptExceptionブロックでThread.currentThread.interrupt()を呼び出すのですか?


回答:


160

これは状態維持するために行われます。

をキャッチしてInterruptExceptionそれを飲み込むと、基本的に、上位レベルのメソッド/スレッドグループが割り込みに気付くことを防ぎます。問題が発生する可能性があります。

を呼び出すことによりThread.currentThread().interrupt()、スレッドの割り込みフラグを設定します。これにより、高レベルの割り込みハンドラーがそれを認識し、適切に処理できるようになります。

Java Concurrency in Practiceでは、これについて第7.1.3章:割り込みへの応答で詳しく説明しています。そのルールは:

スレッドの割り込みポリシーを実装するコードだけが、割り込み要求を飲み込むことができます。汎用タスクとライブラリコードは、割り込み要求を決して飲み込むべきではありません。


15
ドキュメントのことが述べられていますいずれかの方法で投げることによって終了することを、慣例により」InterruptedException ステータス割り込みクリアが。それがそうするとき、私は、これはの面で答え明確になると思う理由を。あなたが割り込みステータスを保持する必要がある
ステリオスAdamantidis

また、他の「配信メカニズム」を介してこの状態に関する通知を受け取ったら、interrupt()呼び出しが割り込みフラグを設定する唯一の方法であることにも注意してくださいInterruptedException
sevo

67

このコードサンプルは、少しわかりやすいと思います。仕事をするクラス:

   public class InterruptedSleepingThread extends Thread {

        @Override
        public void run() {
            doAPseudoHeavyWeightJob();
        }

        private void doAPseudoHeavyWeightJob() {
            for (int i=0;i<Integer.MAX_VALUE;i++) {
                //You are kidding me
                System.out.println(i + " " + i*2);
                //Let me sleep <evil grin>
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread interrupted\n Exiting...");
                    break;
                }else {
                    sleepBabySleep();
                }
            }
        }

        /**
         *
         */
        protected void sleepBabySleep() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

メインクラス:

   public class InterruptedSleepingThreadMain {

        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            InterruptedSleepingThread thread = new InterruptedSleepingThread();
            thread.start();
            //Giving 10 seconds to finish the job.
            Thread.sleep(10000);
            //Let me interrupt
            thread.interrupt();
        }

    }

ステータスを元に戻さずに割り込みを呼び出してみてください。


13
結論は??
スコット混合理论

3
ありがとう。私はあなたが今何を言っているのかわかります: repl.it/@djangofan/InterruptedThreadExample
djangofan

20

注意:

http://download.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

長時間(たとえば、入力待ち)になっているスレッドを停止するにはどうすればよいですか?

この手法が機能するには、割り込み例外をキャッチし、それに対処する準備ができていないメソッドがすぐに例外を再アサートすることが重要です。例外を再スローできるとは限らないため、再スローではなく再アサートと言います。InterruptedExceptionをキャッチするメソッドがこの(チェックされた)例外をスローするように宣言されていない場合は、次のように「それ自体を再割り込み」する必要があります。

Thread.currentThread().interrupt();

これにより、スレッドはできる限りすぐにInterruptedExceptionを再発生させます。


2

私はそれを悪い習慣だと思うか、少なくとも少し危険だと思います。通常、より高いレベルのメソッドはブロッキング操作を実行せず、InterruptedExceptionそこに表示されることはありません。割り込み可能な操作を実行するすべての場所でそれをマスクすると、それを取得することはできません。

Thread.currentThread.interrupt()他の例外(シグナルのinterruptedローカルループ変数をスレッドのメインループに設定するなど)で発生したり、他の例外を発生させたり、シグナルを送信したりしない唯一の理由は、finallyブロックのように、例外を使用して実際には何もできない状況です。

Thread.currentThread.interrupt()通話の意味をよりよく理解したい場合は、PéterTörökの回答を参照してください。


0

java docから参照

このスレッドがwait()、join()、sleep(long)の呼び出しでブロックされている場合、その割り込みステータスはクリアされ、InterruptedExceptionを受け取ります。

このスレッドがI / O操作でブロックされると、スレッドの割り込みステータスが設定され、スレッドはClosedByInterruptExceptionを受け取ります。

このスレッドがセレクターでブロックされている場合、スレッドの割り込みステータスが設定され、選択操作からすぐに戻ります。

前の条件のいずれも保持しない場合、このスレッドの割り込みステータスが設定されます。

そのため、@ Ajay George AnswerのsleepBabySleep()メソッドをI / O操作または単にsysoutに変更した場合、ステータスを元に戻してプログラムを停止する必要はありません。(ところで、InterruptedExceptionはスローされません)

@PéterTörökが言ったように=>これは状態を維持するために行われます。(特に、InterruptedExceptionをスローするメソッドの場合)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.