Java割り込みスレッド(割り込み)超詳細説明

Java割り込みスレッド(割り込み)

@author:Jingdai
@date:2020.10.06

概念

ときにA、スレッドが望んでいるBのスレッドが終了し、我々はそれをどのようにすればよいですか?以前のバージョンのJavaでは、stopこのメソッドを使用してスレッドを終了させることができますが、このメソッドは廃止されたため、使用しないでください。

これAB、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であることがわかりました。これは、このメソッドが呼び出された後、スレッドの中断ステータスをクリアすることを示しています。

  • 中断して無視する

    ここでは、メインスレッドがスレッドを中断しますaThreadaThread、スレッドは無視して、何が起こるかを確認します。コードは次のように表示されます。

    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には他にもブロッキング状況があります。スレッドがInterruptibleChannelIO操作でブロックされている場合、パイプラインはシャットダウンされ、スレッドの割り込みステータスが設定され、ClosedByInterruptException例外がスローされます。

      スレッドがSelectorブロックされている場合、スレッドの割り込みステータスが設定されselectorwakeupメソッドが同じように呼び出されるため、選択操作からすぐに戻るとゼロ以外の値が返される場合があります。

      私はこれらの2種類のブロッキングのどちらも使用していない(不快すぎる)ので、テストするコードを記述しませんでした。後で遭遇したときにテストします。

      上記の場合に加えて、スレッドの割り込みステータスが設定される場合もあります。

参照

  • Java Core Technology Volume1第12章
  • Java8 API

おすすめ

転載: blog.csdn.net/qq_41512783/article/details/108943193