13

メソッドがブロッキングメソッドでなければならない場合、を除外throws InterruptedExceptionすると間違いを犯したと考えるのは正しいですか?

手短に:

  • ブロッキング メソッドに含める必要があるのは、throws InterruptedExceptionそれ以外の場合は通常のメソッドです。
  • ブロッキング メソッドは、いつ完了するかを予測するのが難しいため、応答性が損なわれる可能性がありますthrows InterruptedException

あれは正しいですか?

4

3 に答える 3

27

いいえ、あなたの要約が正しいとは思いません。通常、 をスローする他のメソッドを呼び出すメソッドを作成している場合は、そのメソッドもスローInterruptedExceptionを宣伝する必要があります。InterruptedExceptionただし、依存しているメソッドが中断を通知した場合に何をすべきかについて適切な計画を持っている場合を除きます。

このような中断を吸収できるケースはまれです。おそらく、時間の経過とともに精度が向上する反復解を計算しているのに、呼び出し元のスレッドが中断されたときに、割り当てられた時間内に到達した解で十分であり、返すのに十分正しいと判断したとします。つまり、その解はまだメソッドの範囲内にあります。

想像:

private double improveUpon(double start) throws InterruptedException {
  // ...
}


public double compute() {
  double result = 0.0;
  try {
    do {
      result = improveUpon(result);
    } while (couldBeImproved(result));
  } catch (InterruptedException ex) {
    Thread.currentThread().interrupt();
  }
  return result;
}

代わりに、単に中断要求を尊重したい場合は、InterruptedException関与せずにそうすることができます:

private double improveUpon(double start) {
  // ...
}


public double compute() {
  final Thread current = Thread.currentThread();
  double result = 0.0;
  do {
    result = improveUpon(result);
  } while (couldBeImproved(result) &&
           !current.isInterrupted());
  return result;
}

さらに別のバリエーションとして、メソッドがすべての作業を完了するか、完了できなかったことを呼び出し元に示す必要があり、そこに到達するまでに時間がかかるが、スレッドの中断を尊重したい場合を考えてみましょう。このようなもので十分です:

private double improveUpon(double start) {
  // ...
}


public double compute() throws InterruptedException {
  final Thread current = Thread.currentThread();
  double result = 0.0;
  do {
    if (current.interrupted())
      throw new InterruptedException();
    result = improveUpon(result);
  } while (!isAdequate(result));
  return result;
}

ここで on を呼び出したことに注意してください。これには、スレッドの割り込みステータスが設定されている場合にクリアするThread#interrupted()という副作用があります。そのメソッドが true を返す場合、呼び出し元として、その割り込みステータスを保持して通信する責任を受け入れたことになります。この場合、呼び出し元のスレッドを作成したと仮定せず、割り込みポリシーが何であるかを知るのに十分なスコープがここに表示されていないため、観察して採用した割り込みステータスを throwing で伝えました。InterruptedException

メソッドに「ブロッキング」というラベルを付けるのは、常に程度の問題です。すべてのメソッドは、呼び出し元を一定時間ブロックします。探している違いは、ユーザーがキーを押したり、ネットワーク経由でメッセージが到着したりするなど、何らかの外部入力を待機するメソッドをブロックするかどうかです。このような場合、スローするアドバタイズメントは、レイテンシーを制御する必要があるスレッドからInterruptedExceptionの呼び出し元がメソッドを安全に使用できることを呼び出し元に示します。あなたは、「これが完了するまでに時間がかかるかもしれませんが、あなたが待っているよりも長くはかかりません」と言っています. あなたは、「あなたがやめろと言うまで、私は走る」と言っているのです。これは、たとえば、3 つの条件のいずれかが発生するまでブロックすると脅迫する とは異なります。java.io.InputStream#read()呼び出し元のスレッドが中断されています。

ほとんどの場合、決定は次の質問に答えることに帰着します。

  • メソッドの要件を満たすために、スローするメソッドを呼び出す必要がありますInterruptedExceptionか?
  • もしそうなら、私がその時点までに行った作業は、発信者にとって役に立ちますか?
  • そうじゃないなら俺も投げればいいInterruptedException
  • throws を呼び出さない場合、呼び出しスレッドの割り込みステータスInterruptedExceptionを尊重する必要がありますか?
  • もしそうなら、私が中断されたことを発見するまでに私が行った作業は、私の発信者にとって役に立ちますか?
  • そうでなければ、私は投げるべきInterruptedExceptionです。

現在のスレッドの中断を検出して飲み込む状況は、通常、作成者であるあなたが問題のスレッドを作成し、run()スレッドが中断されたらスレッドのメソッドを終了することを約束した場合に限定されます。これが「協調的取り消し」の概念です。スレッドの実行を停止する要求を観察し、できるだけ早く作業を終了してスレッドの呼び出しスタックを巻き戻すことで、その要求に従うことを決定します。繰り返しになりますが、スレッドのrun()メソッドの作成者でない限り、スレッドの割り込みステータスを飲み込むと、呼び出し元や呼び出し先の他のメソッドの意図した動作が損なわれる可能性があります。

スレッドの中断ステータスThread#isInterrupted()のトピックを調べて、 、Thread#interrupted()、およびのメソッドに慣れることをお勧めしますThread#interrupt()。それらを理解しInterruptedException、飛行中の存在が true を返したことの代替表現Thread#isInterrupted()、または true を返したことの丁寧な翻訳であることを理解したらThread#interrupted()、これはすべてより理にかなっています。

学習するためにさらに例が必要な場合は、そう言ってください。ここに推奨事項を追加できます。

于 2012-06-03T13:17:45.043 に答える
4

InterruptedExceptionメソッドでブロックされたスレッドがinterrupt()呼び出されると、(通常) スローされます。

そのポイントは、ブロックされているスレッドを (何らかの理由で) ブロックを解除することです。理由の例は、アプリケーションのシャットダウンです。そのため、アプリケーションをシャットダウンするときに、スレッドが待機している場合、sleep()またはと言うとwait()、シャットダウンしていることを伝えないと、それらは続行しwait()ます。これらのスレッドがデーモン スレッドでない場合、アプリケーションはシャットダウンしません。

そのため、途中でスレッドが中断されsleep()た場合は、条件を確認して状況を処理する必要があります。シャットダウンの場合は、shutdownフラグを確認し、最終的にクリーンアップ作業を行ってスレッドを手放す必要があります。

他の理由でスレッドが中断されることもありますが、ポイントは同じです。マルチスレッドアプリケーションを使用している場合は、スレッドのプロトコルを確立して、特別な条件が発生したときにそれを処理する方法をスレッドが認識できるようにする必要があります。スレッドが待機中またはスリープ中の場合は、状況を処理するためにスレッドを起動する必要があります。ライブラリまたはフレームワークのクリネットはプロトコルについて何も知らないInterruptedExceptionため、ライブラリ/フレームワークコードで処理することをお勧めするため、処理方法がわかりません。

于 2012-06-03T06:43:24.490 に答える
-2

メソッドがブロックされた場合、それはキャッチして処理する必要がありInterruptedException、再スローしないことを好みます。

また、メソッドはいくつかの場所でブロックする可能性があります。各場所はInterruptedException、投げられる可能性のある場所に適した方法でキャッチして処理する必要があります。

マルチスレッドコードに関する聖書は、JavaConcurrencyinPracticeです。ぜひお読みください。

編集:

並行コードを設計するときは、次のことに注意してください。

  • JVM仕様によると、InterruptedException理由もなくJVMによってランダムにスローされる可能性があります(「スプリアスウェイクアップ」と呼ばれます)
  • 多くのスレッドが同じ条件で待機している可能性があり、すべてが(たとえばによってnotifyAll())ウェイクアップされる可能性がありますが、中断されたときに1つだけが進む可能性があります

したがって、スレッドがウェイクアップされるたびに、待機中の待機条件の状態をチェックし、潜在的に待機に戻る必要があります。

したがって、適切に記述された並行コードはキャッチする必要がありInterruptedExceptionます。再スローするか、独自のアプリケーション固有の例外をスローするかを選択できます。「アプリケーションコード」メソッドは「アプリケーション」例外をスローすることを優先する必要がありますが、待機中のコードが「何が悪かったのか」を理解できない状態になっている場合は、をスローするしかありませんInterruptedException

于 2012-06-03T06:19:39.610 に答える