2

Java Concurrency in Practice の第 7 章を​​読んでいます。

独自のキャンセル ポリシーを持たないが、中断可能なメソッドを呼び出すメソッドについて説明しているセクションで、この本には次のように書かれています。

キャンセルをサポートしていないが、中断可能なブロッキング メソッドを呼び出すアクティビティは、ループ内で呼び出し、中断が検出されたときに再試行する必要があります。この場合、中断ステータスをローカルに保存し、キャッチ直後ではなく、戻る直前に復元する必要があります。中断された例外。

私はこれを完全には理解していません。

メソッドを呼び出すThread.sleepと、ループなどで呼び出す必要があるということですか?

なぜそうすべきなのか誰か説明できますか?

4

4 に答える 4

4

メソッドで Thread.sleep を呼び出します。ループなどで呼び出す必要がありますか?

Thread.sleep()InterruptedException現在のスレッドが (別のスレッドによって) 中断されたときに をスローします。それにどう反応するかはあなたの自由です。誰かがあなたを邪魔しようとしているかどうかに関係なく、眠りたい場合は、そうです、try-catch ブロックの周りに何らかのループを構築する必要があります。おそらく、時計 (例: System.nanoTime()) を使用して、例外がスローされる前にどのくらいスリープしていたかを確認し、残りの時間などをスリープし続ける必要があります。

は、別のスレッドが を呼び出して現在のスレッドに割り込んだ場合にのみInterruptedExceptionスローされることに注意してください。それ自体では発生しないため、通常、スリープなどの周りにループを構築する必要はありません。通常、スレッドは正当な理由 (アプリケーションのシャットダウンなど) でのみ中断されるため、特別な理由がない限り、キャンセル/中断をサポートすることをお勧めします。「特別な理由」には、たとえば、I/O デバイスへの書き込みがあり、キャンセルの試みに関係なく、すべてのデータが書き込まれることを保証しようとすることがあります。(current)Thread.interrupt()

于 2011-10-25T07:13:42.233 に答える
2

最初にいくつかの説明:

スレッドの中断ステータスは基本的にブールフラグであり、によって「true」に設定されinterrupt()ます。このフラグの現在の状態は、を使用して読み取るThread.currentThread().isInterrupted()ことができます。

割り込み可能な操作(Object.wait()またはThread.sleep())が割り込みフラグが設定されていることを検出すると、フラグをスローInterruptedExceptionし、同時にフラグをクリア(「false」に設定)します。これは次のようになります。

if ( Thread.interrupted() ) { throw new InterruptedException(); }

Thread.interrupted()中断されたフラグを暗黙的にクリアすることに注意して覚えてください!これは、catch( InterruptedException ie) {...}が実行されるまでに、スレッド自体がそれが中断されたことを認識しないことを意味します。

そうは言っても、2つの例を見てみましょう。

最初に、キャンセルをサポートするタスクの例。ここでは、タスクが中止される前にどこまで進行するかは実際には気にしません。

  public void run() {

    int x = 0;

    try {

      while (x < 10) {
        Thread.sleep(1000); // Some interruptible operation
        x++;
      }

      System.out.println("x = " + x);

    } catch (InterruptedException ie) {

      System.out.println("Interrupted: x = " + x);

      // We know we've been interrupted. 
      // Let the caller know it, too:
      Thread.currentThread().interrupt();
    }

  }

このコードは、xを0から10までカウントしようとします。中断されない場合は、完了して「x=10」を出力します。ただし、その間にスレッドが中断されると、InterruptedExceptionがスローされ、xをインクリメントする進行中のタスクが中止されます。この場合、出力は、スレッドがいつ中断されたかに応じて、「Interrupted:x = 0」から「Interrupted:x=9」までのいずれかになります。

終了する前にスレッドの中断フラグを復元することをお勧めします。そうしないと、このrun()メソッドの呼び出し元に中断ステータスが表示されないためです。

ここで、タスクを完全に実行することが重要であり、出力が常に「x = 10」になるようにする場合、つまりタスクがキャンセルをサポートしない場合は、別のアプローチが必要です。

  public void run() {
    int x = 0;

    boolean wasInterrupted = false; // <- This is the local variable to store the interruption status

    while (x < 10) {

      wasInterrupted = wasInterrupted || Thread.interrupted(); // not really needed in this case, but for the sake of completeness...

      try {

        Thread.sleep(1000); // <- Some interruptible operation

      } catch (InterruptedException e) {
        wasInterrupted = true;
      }

      x++;
    }

    System.out.println("x = " + x);

    if ( wasInterrupted ) {
      Thread.currentThread().interrupt();
    }

  }

InterruptedExceptionこの場合、タスクが完了するまで、処理を続行します。wasInterrupted良い状態を維持するために、中断を検出した場合は、メソッドから戻る前に中断フラグを正しく設定できるように、その条件をに格納します。

それが意味するものです

中断ステータスをローカルに保存し、戻る直前に復元する必要があります。

この方法で中断を処理する必要は厳密にはないため、「すべき」と表示されます。無視InterruptedException してタスクを完了してから戻ることもできます。ただし、これは上記の良い方法ではなく、シナリオによっては問題が発生する可能性があります。

于 2011-10-27T13:48:04.420 に答える
0

私が理解している限り、それ自体を中断できない、または中断してはならない長時間実行されているサービスは、中断できる他のメソッドを呼び出しています。したがって、この長時間実行されるサービスはこれを検出し、メソッドまたはフラグを介して報告できるはずです。ただし、InterruptedException をスローするだけでなく、操作を再試行できるはずです。

ブロックするメソッドを呼び出すとは、現在の実行がブロックされ、ブロックしているメソッドが値を返すまで待機していることを意味します。これはループで実行できます。メソッド呼び出しが成功したか、呼び出されたメソッドが中断されたかがわかります。

于 2011-10-25T07:10:14.253 に答える
0

私はその本を持っていません。しかし、私が理解している限り、アクティビティが中断された場合 (ちなみに、スリープは割り込み信号ではありません。しかし、割り込み信号を介してスリープからスレッドを目覚めさせることができます)、アクティビティは現在の動的データ (割り込みステータス) を順番に保存する必要があります。自身を復元し、以前の状態から再開します。例えば;

//Let's say you have integer data named "a"...
a = 45646;

//Normally after interruption, and terminating the activity data a is currently
//referencing @memory will be released...

//If you want to continue using data in a you have to save it somewhere
// persistant(Let's say a file)
void onInterruptionDetected()
{
    saveToSomeFile(a, "temp.txt");
}

//After re-execution of activity(Assuming we need a's previous data in order to 
// continue...), we can recover a's data(which is 45646) in previous interruption...
void onResumeDetected()
{
    a = loadFromFile("temp.txt")
}

これが役に立てば幸いです。私はまだ眠いので、エラーが発生する可能性があります:)

于 2011-10-25T07:10:27.467 に答える