web-dev-qa-db-ja.com

誰がJava Thread interrupt()メソッドを呼び出さないのですか?

私は読んで再読しましたJava並行性の実践、私はこの件についていくつかのスレッドを読みました、私はIBMの記事を読みました Dealing with InterruptedException それでも、私が把握していないものが2つあると思います。

  1. 自分で他のスレッドを中断したことがない場合、何がInterruptedExceptionをトリガーできますか?

  2. interrupt()を使用して自分で他のスレッドを中断したことがない場合(毒薬など、作業中のスレッドをキャンセルする他の手段を使用しているため)およびwhile(!cancelled)スタイルループ[両方ともJCIPで説明)]、InterruptedException次に意味?捕まえたらどうすればいいですか?アプリをシャットダウンしますか?

82
SyntaxT3rr0r

スレッド割り込みメカニズムは、実行中の動作を停止する要求に応答する(協調する)スレッドを取得する好ましい方法です。すべてのスレッド(私が思うスレッド自体を含む)は、スレッドでinterrupt()を呼び出すことができます。

実際には、interrupt()の通常のユースケースには、何らかの種類のフレームワークまたはマネージャーが何らかの作業スレッドに実行を停止するよう指示することが含まれます。ワーカースレッドが「割り込み対応」の場合、例外を介して、または割り込みフラグを定期的に確認することで、スレッドが割り込みを受けたことがわかります。正常に動作するスレッドは、中断されたことに気づくと、実行中の処理を放棄して終了します。

上記のユースケースを想定すると、コードがJavaフレームワーク内または何らかのワーカースレッドから実行される場合、コードは中断される可能性があります。あなたのコードがどのように呼ばれたかに応じて、これは適切な例外を返すか投げることによって行われるかもしれませんが、おそらくSystem.exit()を呼び出すべきではありません。それが中断された理由を必ずしも知っているわけではなく、フレームワークによって中断される必要がある他のスレッドがあるかどうかは確かにわかりません。

一方、コードが何らかのフレームワークの制御下で実行するように設計されていない場合、InterruptedExceptionは予期しない例外であると主張できます。つまり、バグ。その場合、他のバグと同様に例外を処理する必要があります。例えば未チェックの例外でラップし、他の予期しない未チェックの例外と同じポイントでキャッチしてログに記録します。 (あるいは、アプリケーションは単に割り込みを無視し、それがしていたことを続けることができます。)


1)自分で他のスレッドを中断したことがない場合、InterruptedExceptionをトリガーできるものは何ですか?

1つの例は、Runnableを使用してExecutorServiceオブジェクトが実行され、shutdownNow()がサービスで呼び出される場合です。そして理論的には、サードパーティのスレッドプールまたはスレッド管理フレームワークは、このようなことを合法的に行うことができます。

2)interrupt()を使用して自分で他のスレッドを中断したことがない場合... InterruptedExceptionはどういう意味ですか?捕まえたらどうすればいいですか?アプリをシャットダウンしますか?

コードベースを分析して、何がinterrupt()呼び出しを行っているのか、そしてその理由を把握する必要があります。それがわかったら、アプリの>> your <<の部分で何をする必要があるかを判断できます。

InterruptedExceptionがスローされる理由がわかるまで、ハードエラーとして扱うことをお勧めします。例えばスタックトレースをログファイルに出力し、アプリをシャットダウンします。 (明らかに、それは必ずしも正しい答えではありません...しかし、ポイントはこれが「バグ」であり、開発者/メンテナーの注意を引く必要があるということです。)

3)interrupt()を呼び出している人/何を見つけるにはどうすればよいですか?

これに対する良い答えはありません。私が提案できる最善の方法は、Thread.interrupt()にブレークポイントを設定し、コールスタックを調べることです。

48
Stephen C

コードを他のライブラリと統合することにした場合、それらはあなたのコードでinterrupt()を呼び出すことができます。例えば将来、 ExecutorService 内でコードを実行することに決めた場合、interrupt()を介して強制的にシャットダウンする可能性があります。

簡単に言うと、コードが実行されている場所nowだけでなく、将来どのようなコンテキストで実行されるかも考えます。例えばあなたはそれを図書館に入れるつもりですか?コンテナ ?他の人はどのようにそれを使用しますか?再利用しますか?

12
Brian Agnew

他の人が指摘したように、スレッドの中断(実際には、ブロッキング呼び出しの中断)は通常、正常に終了するか、進行中のアクティビティをキャンセルする目的で使用されます。

ただし、InterruptedExceptionのみを「終了コマンド」として扱わないでください。代わりに、Object.notify()と同じように、割り込みをスレッドの実行状態を制御する手段と考える必要があります。 Object.wait()の呼び出しから目覚めた後、現在の状態を確認するのと同じように(目覚めは待機条件が満たされたことを意味するとは思わない)、割り込みでナッジされた後why中断されたことを確認する必要があります。通常、これを行う方法があります。たとえば、_Java.util.concurrent.FutureTask_にはisCancelled()メソッドがあります。

コードサンプル:

_public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'Nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}
_
9

質問の問題は「私」です。 「I」は通常、クラスの単一のインスタンスを指します。つまり、特定の低レベルコード(クラス)は、システム全体の実装に依存すべきではありません。あなたは、いくつかの「建築上の」決定をしたと言っていました(実行するプラットフォームなど)。

JREから発生する可能性のある予期しない割り込みは、Java.util.concurrentおよびアプレットのシャットダウン。

スレッド割り込みの処理は通常、誤って記述されています。したがって、可能な限り割り込みの発生を回避するためのアーキテクチャ上の決定をお勧めします。ただし、割り込みを処理するコードは常に正しく記述する必要があります。現在、プラットフォームから割り込みを取得できません。

これは、独自のスレッドクラスを作成し(_Java.lang.Thread_を拡張)、interrupt()メソッドをオーバーライドすることで学習できます。このメソッドでは、スタックトレースをStringフィールドなどに記録してから、super.interruptに転送します()。

_public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}
_
2
weekens

既に述べたように、別のライブラリがスレッドを中断する可能性があります。ライブラリがコードからスレッドに明示的にアクセスしていなくても、実行中のスレッドのリストを取得し、次の method でスレッドを中断することができます。

1
mangoDrunk

InterruptedExceptionは、ルーチンmayが中断されると言いますが、必ずしも中断されるとは限りません。

割り込みを予期しない場合は、他の予期しない例外と同様に扱う必要があります。予期しない例外によって重大な結果が生じる可能性があるクリティカルセクションにある場合は、リソースをクリーンアップして正常にシャットダウンすることをお勧めします(割り込みに依存しない適切に設計されたアプリケーションが使用されているため、割り込み信号を取得するため)ある意味では設計されていなかったので、何か間違っているはずです。あるいは、問題のコードが重要ではない、または些細なものである場合、割り込みを無視(またはログ記録)して続行します。

0
Ash

私はあなたが中断について少し混乱している理由を理解していると思う。行の私の答えを考慮してください:

自分で他のスレッドを中断したことがない場合、何がInterruptedExceptionをトリガーできますか?

まず、他のスレッドを中断することがあります。 JCiPでは、自分が所有していないスレッドを決して中断してはならないということを知っています。ただし、このステートメントは適切に理解する必要があります。つまり、任意のスレッドで実行されている可能性のあるコードは、スレッドの所有者ではないため、割り込みポリシーの手がかりがないため、割り込みを処理すべきではありません。そのため、他のスレッドで割り込みを要求することもできますが、その所有者に割り込みアクションを実行させることができます。タスクコードではなく、中断ポリシーがカプセル化されています。少なくとも割り込みフラグを設定するように注意してください!

中断、JVM割り込みなどがまだある可能性がある理由はたくさんあります。

Interrupt()を使用して自分で他のスレッドを中断したことがない場合(たとえば、ポイズンピルやwhile(!cancelled)スタイルループ(両方ともJCIPで説明)など、作業スレッドをキャンセルする他の手段を使用しているため) InterruptedExceptionはどういう意味ですか?捕まえたらどうすればいいですか?アプリをシャットダウンしますか?

ここでは非常に注意する必要があります。 InterruptedException(IE)をスローしたスレッドを所有している場合、キャッチするとどうなるかわかります。たとえば、アプリ/サービスをシャットダウンするか、この強制終了されたスレッドを新しいスレッドに置き換えることができます。ただし、スレッドを所有していない場合は、IEを呼び出しスタックの上位に再スローするか、何か(ロギングなど)を実行した後、割り込みステータスをリセットして、所有するコードがこのスレッドは、制御が到達すると、スレッドが割り込まれたことを知ることができ、割り込みポリシーのみを知っているため、アクションを実行できます。

これが役に立てば幸いです。