Java割り込みスレッド(割り込み)
@author:Jingdai
@date:2020.10.06
概念
ときに
A
、スレッドが望んでいるB
のスレッドが終了し、我々はそれをどのようにすればよいですか?以前のバージョンのJavaでは、stop
このメソッドを使用してスレッドを終了させることができますが、このメソッドは廃止されたため、使用しないでください。これ
A
でB
、threadinterrupt()
メソッドでthreadを呼び出しB
て、独自のスレッドを終了させたいことがわかりますがB
、スレッドを自分で終了するかどうかによって異なりますB
が、終了要求は無視できます。(もちろん、これを行わない方が良いです)詳細を見てみましょう。
関連機能紹介
void interrupt()
このスレッドを中断します。
boolean isInterrupted()
このスレッドが中断されていないか確認してください。
static boolean interrupted()
現在のスレッドが中断されているかどうかを確認します。このメソッドは、呼び出された後のスレッドの中断ステータスもクリアします。
説明例
boolean isInterrupted()
メソッドとstatic boolean interrupted()
メソッドの違いまず、次のコードテスト
boolean isInterrupted()
メソッド。public static void main(String[] args) { Thread.currentThread().interrupt(); System.out.println(Thread.currentThread().isInterrupted()); // true System.out.println(Thread.currentThread().isInterrupted()); // true }
出力は両方の時間であることがわかります
true
。次に、
static boolean interrupted()
メソッドをテストします。public static void main(String[] args) { Thread.currentThread().interrupt(); System.out.println(Thread.interrupted()); // true System.out.println(Thread.interrupted()); // false }
テストでは、最初の出力がtrueで、2番目の出力がfalseであることがわかりました。これは、このメソッドが呼び出された後、スレッドの中断ステータスをクリアすることを示しています。
中断して無視する
ここでは、メインスレッドがスレッドを中断します
aThread
がaThread
、スレッドは無視して、何が起こるかを確認します。コードは次のように表示されます。public static void main(String[] args){ // create and start aThread Runnable r = () -> { while (true) { System.out.println("I'm alive"); } }; Thread aThread = new Thread(r); aThread.start(); // interrupt aThread aThread.interrupt(); }
テストで
aThread
は、実行中のスレッドの影響が見つからなかったか、出力されましたI'm alive
。一般的な使用法
割り込みを処理しないと効果がないので、どのように対応すればよいですか?スレッドが中断されているかどうかは常に判断する必要があります。スレッドが中断された場合は、現在のタスクの要件に従って次の作業を選択し、スレッドが終了する前に必要なリソースを閉じる必要があります。以下のコードを見てください。
public static void main(String[] args){ // create and start aThread Runnable r = () -> { try { while (!Thread.currentThread().isInterrupted()) { //do work System.out.println("I'm alive"); } System.out.println("I ll die"); } finally { // close some resources } }; Thread aThread = new Thread(r); aThread.start(); try { Thread.currentThread().sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } // interrupt aThread aThread.interrupt(); }
スレッドが中断されていない場合、そのマンデートを実装している場合、中断されている場合、スレッドはループから外れ
finally
、対応するリソースを閉じて、クリーンアップと操作を実行します。スレッドがブロックされたとき
上記の状況は、ブロックされていないスレッドで実行できますが、スレッドがブロックされると、スレッドはスレッドの割り込みステータスを確認できないため、
InterruptedException
ブロックを解除するための例外が導入されます。次のように、異なるブロッキングの間にはいくつかの違いがあります。
スレッド
sleep()
メソッドまたはjoin()
メソッドがブロックする場合次のコード:
public static void main(String[] args) { // create and start aThread Runnable r = () -> { try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { System.out.println("die"); e.printStackTrace(); } finally { // close some resources } }; Thread aThread = new Thread(r); aThread.start(); try { Thread.currentThread().sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // interrupt aThread aThread.interrupt(); }
メソッドが実行されなくなった
interrupt()
ときにこれらのスレッドを呼び出すとsleep()/join()
、メソッドは実行されなくなり、割り込みステータスがクリアされ、catch
実行中のブロックに直接ジャンプします。したがって、ループsleep()
メソッドを呼び出すと、割り込みステータスは検出されません。catch
実行中のブロックを直接ジャンプしますが、InterruptedException
例外を直接キャプチャする必要があります。スレッドは
wait()
、メソッドがブロックするときですスレッドとは
wait()
、メソッドをブロックするとき、interrupt()
エフェクトを呼び出すとき、スレッドメソッドはsleep()
メソッドであるかjoin()
、本質的に同じ方法でエフェクトをcatch
ブロックするときです。また、割り込みステータスをクリアし、実行するためにブロックにジャンプします。ただし、少し異なります。つまり、interrupt()
呼び出し元のスレッドは呼び出されたwait()
ロックオブジェクトメソッドを取得します。完成したオブジェクトを取得した後、ロックしcatch
て実行するブロックにスローします。ロックを取得しないと、スローすることはできません。異常catch
はブロックに入ることができません。次のコードは、最初のaThread
ロックを取得し、wait
(ノートwait()
、その後、メソッドはロックを解除します)bThead
ロックを取得しますが、b
ロックを解除することはありません、でaThread
wait
時間、メインスレッドの呼び出しinterrupt()
割り込みにaThread
、しかしので、aThread
ロックを取得することはありませんので、それがします例外をスローせず、catch
ブロック操作に入りません。コードは以下のように表示されます。public static void main(String[] args) { Runnable r = () -> { try { synchronized (o) { System.out.println("aThread get lock"); o.wait(10000); } } catch (InterruptedException e) { e.printStackTrace(); // can't come here } }; Thread aThread = new Thread(r); aThread.start(); Runnable r2 = () -> { try { Thread.currentThread().sleep(250); synchronized (o) { System.out.println("bThread get lock"); while (true) { } } } catch (InterruptedException e) { e.printStackTrace(); } }; Thread bThread = new Thread(r2); bThread.start(); try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // interrupt aThread aThread.interrupt(); }
その他のブロッキング
APIには他にもブロッキング状況があります。スレッドが
InterruptibleChannel
IO操作でブロックされている場合、パイプラインはシャットダウンされ、スレッドの割り込みステータスが設定され、ClosedByInterruptException
例外がスローされます。スレッドが
Selector
ブロックされている場合、スレッドの割り込みステータスが設定されselector
、wakeup
メソッドが同じように呼び出されるため、選択操作からすぐに戻るとゼロ以外の値が返される場合があります。私はこれらの2種類のブロッキングのどちらも使用していない(不快すぎる)ので、テストするコードを記述しませんでした。後で遭遇したときにテストします。
上記の場合に加えて、スレッドの割り込みステータスが設定される場合もあります。
参照
- Java Core Technology Volume1第12章
- Java8 API