16

次のような長時間実行されるタスクがあります。

public void myCancellableTask() {
    while ( someCondition ) {
       checkIfCancelRequested();
       doSomeWork();
    }
 }

タスクはキャンセルできます (キャンセルが要求され、checkIfCancelRequested() がキャンセル フラグをチェックします)。通常、このようなキャンセル可能なループを記述するときは、フラグを使用してキャンセルが要求されたことを示します。しかし、Thread.interrupt を使用して、スレッドが中断されたかどうかを確認することもできます。どちらが好ましいアプローチなのか、そしてその理由はよくわかりません。

ありがとう、

ジェフ

4

5 に答える 5

22

割り込みを使用する際の問題の 1 つは、実行中のすべてのコードを制御しないと、他の誰かが自分のライブラリで割り込みを処理する方法を理解していないために、割り込みが「適切に」機能しないリスクがあることです。つまり、API は、依存する s の処理に関する API を目に見えないようにエクスポートします。interrupt

あなたの例でdoSomeWorkは、サードパーティの JAR にあり、次のようになっているとします。

public void doSomeWork() {
    try { 
        api.callAndWaitAnswer() ; 
    } 
    catch (InterruptedException e) { throw new AssertionError(); }
}

AssertionError次に、 (または使用しているライブラリがスローする可能性のある他のもの)を処理する必要があります。経験豊富な開発者が、割り込みを受け取ったときにあらゆる種類のナンセンスをスローするのを見てきました! 一方、メソッドは次のようになっている可能性があります。

public void doSomeWork() {
    while (true) {
        try { 
            return api.callAndWaitAnswer() ; 
        } 
        catch (InterruptedException e) { /* retry! */ }
    }
}

この割り込みの「不適切な処理」により、プログラムが無期限にループします。繰り返しますが、これをばかげていると片付けないでください。壊れた割り込み処理メカニズムがたくさんあります。

少なくとも独自のフラグを使用すると、サードパーティのライブラリからは完全に見えなくなります。

于 2009-12-16T14:35:39.300 に答える
8

割り込みは、指定された待機条件のリストからスレッドを爆破します。あなた自身のキャンセルフラグはそうではありません。IO とイベントの待機を中断する場合は、interrupt を使用します。それ以外の場合は、独自のものを使用してください。

于 2009-12-16T14:17:28.057 に答える
1

実装に依存しdoSomeWork()ます。それは純粋な計算ですか、それとも (任意の時点で) API (IO など) 呼び出しのブロックを伴いますか? bmargulies回答によると、JDK の多くのブロッキング API は中断可能であり、中断された例外をスタックに伝播します。

そのため、作業に潜在的なブロッキング アクティビティが伴う場合は、フラグを使用してプロセスを制御することにした場合でも割り込みを考慮する必要があり、割り込みを適切にキャッチして処理/伝播する必要があります。

さらに、フラグに依存する場合は、フラグがvolatileセマンティクスで宣言されていることを確認してください。

于 2009-12-16T14:34:57.987 に答える
0

ほとんどの場合、それは好みの問題だと思います。個人的には手作りの旗を買いに行きます。これにより、より詳細な制御が可能になります。たとえば、この方法で、スレッドが他のオブジェクトを一貫性のない状態のままにしないようにします。さらに、パフォーマンスが非常に重要な場合は、例外の使用にはオーバーヘッドがあることに注意してください(99%のケースで無視できる場合でも)。

于 2009-12-16T14:29:42.790 に答える