序文
中断したExceptionの場合、それを処理する一般的な方法は、それを「飲み込む」ことです - それをキャッチして何もしない(または記録しますが、それはそれほど良くありません) - リスト4の後に。残念ながら、このアプローチは、この期間中に割り込みが発生する可能性があり、割り込みがアプリケーションがアクティビティをキャンセルしたり、時間内に閉鎖する能力を失う可能性があるという事実を無視します。
ブロッキング方法
メソッドが中断されたエクセプトをスローすると、特定のチェック例外をスローできることを伝えるだけでなく、何か他のものも伝えます。たとえば、それはブロッキング方法であることがわかります。これは、適切に応答する場合、ブロッキングを排除し、できるだけ早く戻ってきます。
ブロッキング方法は、実行に時間がかかる一般的な方法とは異なります。一般的な方法の完了は、それが何をしているのか、利用可能な十分なコンピューティングリソースがあるかどうか(CPUサイクルとメモリ)のみに依存します。ブロッキング方法の完了は、タイマーの有効期限、I/Oの完了、または別のスレッドのアクションなどの一部の外部イベントにも依存します(ロックを解放、フラグの設定、または作業キューにタスクを配置します)。一般的な方法は、作業が完了した後に終了しますが、ブロック方法は外部イベントに依存するため、予測がより困難です。ブロッキング方法は、いつ終了するかを予測することが困難であるため、応答性に影響を与える可能性があります。
ブロッキング方法は、待機しているイベントを待つことができないため終了しない可能性があるため、ブロッキングメソッドをキャンセルできるようにすることが非常に便利です(長期にわたる非ブロッキングメソッドがキャンセルできる場合に非常に便利です)。キャンセル可能な操作とは、通常の完了前に外部から終了できる操作を指します。 threadによって提供され、thread.sleep()とobject.wait()によってサポートされる割り込みメカニズムはキャンセルメカニズムです。 1つのスレッドが別のスレッドを要求して、それがしていることを停止できるようにします。メソッドが中断されたエクセプトをスローすると、メソッドを実行するスレッドが中断された場合、それがしていることを止めて事前に戻り、中断したエクセプトをスローすることにより、事前に戻ります。行儀の良いブロッキングライブラリメソッドは、割り込みに応答し、中断のエクセプトをスローして、応答に影響を与えることなくキャンセル可能なアクティビティで使用できるようにする必要があります。
スレッド割り込み
各スレッドには、スレッドの中断されたステータスを表します。割り込み状態は最初は偽です。別のスレッドがthread.interrupt()を呼び出してスレッドを中断すると、2つの状況のいずれかが発生します。そのスレッドがthread.sleep()、thread.join()、またはobject.wait()などの低レベルの中断可能なブロッキングメソッドを実行している場合、ブロックを解除して中断exceptionをスローします。それ以外の場合は、割り込み()がスレッドの割り込み状態を設定するだけです。中断されたスレッドで実行されているコードが中断状態を投票して、それがしていることを停止するように要求されているかどうかを確認できます。割り込み状態は、thread.isinterrupted()で読み取ることができ、swarch.interrupded()という名前の操作によって読み取られてクリアできます。
中断は共同メカニズムです。あるスレッドが別のスレッドを中断すると、中断されたスレッドが必ずしもすぐにやっていることを停止するわけではありません。代わりに、割り込みは別のスレッドへの丁寧な要求であり、それが喜んで便利なときにそれがしていることを止めることです。 Thread.sleep()などのいくつかの方法は、そのような要求を非常に真剣に受け止めますが、各方法は必ずしも割り込みに応答するわけではありません。割り込みリクエストの場合、ブロックされていないが実行に時間がかかる方法は、割り込みステータスをポーリングし、中断したときに事前に戻ることができます。あなたは自由に割り込み要求を無視することができますが、そうすることで応答に影響します。
中断の共同性の性質の1つの利点は、キャンセル可能なアクティビティを安全に構築するためのより大きな柔軟性を提供することです。アクティビティがすぐに停止することはめったにありません。更新が進行中にアクティビティがキャンセルされた場合、プログラムデータ構造が一貫性がない場合があります。割り込みにより、キャンセル可能なアクティビティが進行中の作業をクリーンアップし、侵入を復元し、終了する前にキャンセルされることを他のアクティビティに通知することができます。
HALDNTIRTEREDEXCEPTION
中断exceptionをスローすることは、メソッドがブロッキングメソッドであることを意味する場合、ブロッキング方法を呼び出すことは、メソッドもブロッキング方法であることを意味し、中断exceptionを処理するための何らかの戦略が必要です。最も簡単な戦略は、通常、Puttask()およびgetTask()メソッドのコードに示されているように、自分で中断したエクセプトをスローすることです。
リスト1。中断されたエクセプトをキャッチしない、発信者に伝播する
パブリッククラスのタスク{private static final int max_tasks = 1000; private blockingqueue <task> queue = new linkedblockingqueue <task>(max_tasks); public void puttask(タスクr)スローが中断されたexception {queue.put(r); } public task gettask()throws arturnedexception {return queue.take(); }}例外が伝播される前に、いくつかのクリーニング作業が必要な場合があります。この場合、中断されたExceptionをキャッチし、クリーンアップを実行してから、例外をスローできます。リスト2は、オンラインゲームサービスのプレーヤーを一致させるために使用されるメカニズムであるこの手法を示しています。 MatchPlayers()メソッドは、2人のプレイヤーが到着するのを待ってから、新しいゲームを開始します。 1人のプレーヤーが到着したときにメソッドが中断されているが、別のプレーヤーが到着していない場合、そのプレイヤーがキューに戻り、プレイヤーのリクエストがゲームへのリクエストが失われないように、エクセプトを中断します。
リスト2。中断端切りを再投与する前に、タスク固有のクリーンアップ作業を実行します
Public Class PlayerMatcher {プライベートプレイヤーソースプレーヤー。 public PlayerMatcher(playersource players){this.players = players; } public void matchplayers()throws arturtedexception {try {player playerone、playertwo; while(true){playerone = playertwo = null; // 2人のプレイヤーが到着するのを待って、新しいGame PlayerOne = player.waitforplayer(); // ie playertwo = player.waitforplayer(); // IE StartNewGame(playerOne、playertwo)を投げることができます。 }} catch(arturnedexception e){// 1人のプレイヤーを取得して中断した場合、そのプレイヤーを戻してください(playerone!= null)player.addfirst(playerone); //その後、例外を伝播しますe。 }}}飲み込むのをやめないでください
たとえば、runnableによって定義されたタスクが中断可能な方法を呼び出す場合、中断exceptionを投げることは適切ではない場合があります。この場合、中断されたエクセプトを再投与することはできませんが、何もしたくありません。ブロッキングメソッドが割り込みを検出し、中断のエクセプトをスローすると、割り込み状態がクリアされます。中断されたエクセプトがキャッチされているが再投与できない場合、中割り込みの証拠を発生させて、コールスタック内の高レベルのコードが割り込みを知り、それに応答できるようにする必要があります。このタスクは、リスト3に示すように、curtre()を呼び出して現在のスレッドを「再頻繁に」することで実行できます。少なくとも、中断exceptionがキャッチされ、再投げられない場合はいつでも、現在のスレッドが再停止されます。
リスト3。中断exceptionをキャプチャした後、中断状態を再開します
Public Class TaskRunnerはRunnable {private blockingqueue <task> queue;を実装しています。 public TaskRunner(blockingQueue <task> queue){this.queue = queue; } public void run(){try {while(true){task task = queue.take(10、timeunit.seconds); task.execute(); }} catch(arturnedexception e){//割り込まれたステータスthread.currentthread()。 }}}中断exceptionを扱うときに最悪のことは、それを生で飲み込むことです - それをキャッチし、それを再投与したり、スレッドの割り込み状態を再アサートしたりすることもありません。対処方法がわからない例外の場合、対処する最も標準的な方法は、それをキャッチして記録することですが、この方法はまだ生の割り込みのようなものです。 (誰かがログを読むようになったときに処理するには手遅れであるため、中断exceptionを記録することは賢明ではありません。)リスト4は、広く使用されているパターンを示しています。これは、生の嚥下中断のパターンでもあります。
リスト4。生の嚥下中断 - これを行わないでください
//このパブリッククラスのタスクランナーは実行可能{private blockingqueue <task> queue; public TaskRunner(blockingQueue <task> queue){this.queue = queue; } public void run(){try {while(true){task task = queue.take(10、timeunit.seconds); task.execute(); }} catch(arternedexception wallowed){ / *これを行わない - 代わりに中断されたステータスを復元 * /}}}}割り込みリクエストの処理を計画しているかどうかに関係なく、中断されたエクセプトを再投与できない場合、1つの割り込み要求に複数の「受信機」がある可能性があるため、現在のスレッドを再インターする必要があります。標準のスレッドプール(ThreadPoolexecutor)ワーカースレッドの実装は中断の責任があるため、実行中のスレッドプールでタスクを中断することで二重の効果があります。 1つはタスクをキャンセルすることであり、もう1つはスレッドプールが閉じようとしていることを実行スレッドに通知することです。タスクがリクエストを食い尽くす場合、ワーカースレッドは要求された割り込みがあることを知らず、アプリケーションまたはサービスのシャットダウンを遅らせます。
キャンセルされたタスクを実装します
言語仕様の割り込みの特定のセマンティクスはありませんが、大規模なプログラムでは、キャンセルを除いて割り込みセマンティクスを維持することは困難です。アクティビティとは異なり、ユーザーはGUIまたはJMXやWebサービスなどのネットワークメカニズムを介してキャンセルを要求できます。プログラムロジックは、キャンセルするように要求することもできます。たとえば、ディスクがいっぱいであることを検出した場合、Web Crawlerは自動的にシャットダウンします。そうしないと、並列アルゴリズムがソリューション空間の異なる領域を検索するために複数のスレッドを起動し、スレッドの1つが解決策を見つけたらそれらのスレッドをキャンセルします。
タスクがキャンセルできるからといって、割り込み要求をすぐに応答する必要があるという意味ではありません。ループ内のコードを実行するタスクの場合、通常、ループイテレーションごとに割り込みを1回チェックする必要があります。ループが実行される時間に応じて、コードがスレッドが中断されていることに気付くまでに時間がかかる場合があります(thread.isinterpurded()メソッドを呼び出すことにより、割り込み状態を投票するか、ブロッキングメソッドを呼び出します)。タスクが応答する必要がある場合、割り込み状態をより頻繁にポーリングできます。ブロッキング方法は通常、インターレットで割り込み状態を直ちにポーリングし、応答性を向上させるように設定されている場合、中断のエクセプトも投げます。
嚥下を止めることができるのは、スレッドが終了しようとしていることを知っていることだけです。このシナリオは、リスト5に示すように、中断可能なメソッドを呼び出すクラスがスレッドの一部であり、実行可能または一般的なライブラリコードの一部である場合にのみ発生します。リスト5は、中断されるまでプライム番号をリストするスレッドを作成します。プライムチェックの検索に使用されるループは、2つの場所で中断をチェックします。1つは、whileループのヘッドでis utterrurded()メソッドをポーリングすることです。もう1つはブロッキングメソッドを呼び出すことです。
リスト5。スレッドが終了しようとしていることがわかっている場合は、割り込みを飲み込むことができます
パブリッククラスPrimeProducerはスレッドを拡張します{プライベートファイナルブロッキングキュー<BigInteger> Queue; PrimeProducer(BlockingQueue <Biginteger> Queue){this.queue = queue; } public void run(){try {biginteger p = biginteger.one; while(!thread.currentthread()。is interrupted())queue.put(p = p.nextprobableprime()); } catch(interruptedexceptionが消費){ / *スレッドが終了することを許可 * /}} public void cancel(){interrance(); }}壊れないブロッキング方法
すべてのブロッキングメソッドが中断されたエクセプトをスローするわけではありません。 I/Oが完了するのを待っている入力および出力ストリームクラスはブロックされますが、中断したExceptionを投げず、中断しても事前に戻りません。ただし、ソケットI/Oの場合、スレッドがソケットを閉じると、そのソケットのブロッキングI/O操作が早期に終了し、ソケットエクセプションがスローされます。 Java.nioの非ブロッキングI/Oクラスは、割り込み可能なI/Oをサポートしていませんが、チャンネルを閉じたり、セレクターで目覚めを要求したりすることでブロック解除することもできます。同様に、内部ロックを取得しようとすること(同期ブロックの入力)を中断することはできませんが、ReentrantLockは中断可能な取得モードをサポートします。
無関心なタスク
一部のタスクは中断されることを拒否しているため、それらは廃止されません。ただし、非キャネル不可能なタスクでさえ、コールスタック上の高レベルのコードが、キャンセル不可能なタスクが終了した後に割り込みを処理する必要がある場合に割り込み状態を保持しようとする必要があります。リスト6は、中断されているかどうかに関係なく、利用可能なアイテムがキューに表示されるまでブロッキングキューを待つ方法を示しています。便利なため、最終的なブロックで終了した後、割り込み状態を再開します。 (以前に割り込み状態を再開することはできません。これにより、無限のループが発生するため、BlockingQueue.take()はすぐに入り口で割り込み状態を投票します。
リスト6。戻る前に中断状態を復元する無セルなタスク
パブリックタスクgetNextTask(blockingQueue <task> queue){boolean挿入= false; try {while(true){try {return queue.take(); } catch(arturnedexception e){挿入= true; //転倒してretry}}} fullly {if(挿入)shood.currentthread()。arturn(); }}要約します
Javaプラットフォームが提供するコラボレーション割り込みメカニズムを使用して、柔軟なキャンセル戦略を構築できます。アクティビティは、キャンセル可能かキャンセルできないか、または割り込みに応答する方法を自分の裁量で決定できます。また、即時のリターンがアプリケーションの整合性を損なう場合、割り込みを延期することもできます。コード内の割り込みを完全に無視したい場合でも、割り込み状態を再投与せずに中割り込み状態が復元されていることを確認してください。上記は、Javaの理論と中断のあるException例外を処理する実践の完全な内容です。この記事があなたに役立つことを願っています。ご質問がある場合は、議論のためのメッセージを残してください。