web-dev-qa-db-ja.com

catch InterruptExceptionブロックでThread.currentThread.interrupt()を呼び出す理由

CatchブロックでThread.currentThread.interrupt()メソッドを呼び出すのはなぜですか?

135
Hesey

これはkeep stateに行われます。

InterruptExceptionをキャッチして飲み込むと、本質的に、より高いレベルのメソッド/スレッドグループが割り込みに気付かないようにします。問題を引き起こす可能性があります。

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

Javaの並行性の実践 では、これについて詳しく説明しています第7.1.3章:割り込みへの応答。そのルールは次のとおりです。

スレッドの割り込みポリシーを実装するコードのみが割り込み要求を飲み込む可能性があります。汎用タスクおよびライブラリコードは、割り込み要求を決して飲み込まないでください。

144
Péter Török

このコードサンプルは、物事を少し明確にしていると思います。仕事をするクラス:

   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();
        }

    }

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

63
Ajay George

注意:

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

長時間(入力など)待機するスレッドを停止するにはどうすればよいですか?

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

Thread.currentThread().interrupt();

これにより、スレッドは可能な限りすぐにInterruptedExceptionをリレイズします。

20
Bert F

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

Thread.currentThread.interrupt()の唯一の理論的根拠であり、他の方法で他の例外を発生させたり、割り込み要求を通知したりしない(たとえば、スレッドのメインループでinterruptedローカル変数変数を設定する) finallyブロックのように、例外で何もしません。

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

2
Piotr Findeisen