Java interrupt()方法使用注意_動力ノードJava学院の整理

9186 ワード

プログラムは簡単です。しかし、プログラマーの前では、スレッドが新たな難題を呈しています。適切に解決されていないと、思いがけない行動や些細で発見しにくいエラーが発生します。
本論文では、これらの課題の一つについて、どのようにスレッドを停止させますか?
背景
    中断(Interrupt)スレッドは、スレッドがタスクを完了する前に進行中のすべてを停止し、その現在の動作を効果的に停止することを意味する。スレッドが死亡しているか、新しいタスクを待っているか、または次のステップに進み続けるかは、このプログラムに依存します。初めて見ると簡単に見えるかもしれませんが、希望の結果を達成するために警告をしなければなりません。以下のいくつかの警告を覚えたほうがいいです。
    まず、Thread.stop方法を忘れます。確かに実行中のスレッドを停止しましたが、この方法は安全ではなく、提唱されていません。これは将来のJavaバージョンには存在しなくなります。
    軽率な連中は別の方法でThread.interruptに惑わされるかもしれない。名前は何かを暗示しているようですが、この方法は、Listing Aで説明したように、実行中のスレッドを中断することはありません。これはスレッドを作成し、Thread.interrupt方法を使ってスレッドを停止しようとします。Thread.sleep()メソッドの呼び出しは、スレッドの初期化と中止に十分な時間を提供する。スレッド自体は、有用な動作には一切関与していない。
Listing A 

class Example1 extends Thread { 
    boolean stop=false; 
    public static void main( String args[] ) throws Exception { 
    Example1 thread = new Example1(); 
    System.out.println( "Starting thread..." ); 
    thread.start(); 
    Thread.sleep( 3000 ); 
    System.out.println( "Interrupting thread..." ); 
    thread.interrupt(); 
    Thread.sleep( 3000 ); 
    System.out.println("Stopping application..." ); 
    //System.exit(0); 
    } 
    public void run() { 
    while(!stop){ 
    System.out.println( "Thread is running..." ); 
    long time = System.currentTimeMillis(); 
   while((System.currentTimeMillis()-time < 1000)) { 
    } 
    } 
    System.out.println("Thread exiting under request..." ); 
    } 
    } 
Listing Aのコードを実行したら、コンソールで以下の出力が見られます。
Starting thread…
Thread is running…
Thread is running…
Thread is running…
Interrupting thread…
Thread is running…
Thread is running…
Thread is running…
Stopingアプリ…
Thread is running…
Thread is running…
Thread is running…
………
さらに、Thread.interrupt()が呼び出された後も、スレッドは続行されます。
スレッドを本当に中断します。
    中断スレッドが一番良いのは、共有変数(shared variable)を使って信号を送り、スレッドが実行中のジョブを停止しなければならないということです。スレッドは、この変数(特に冗長動作中)を定期的にチェックして、タスクを秩序正しく停止しなければならない。Listing Bはこの方式を説明している。
Listing B 

class Example2 extends Thread { 
 volatile boolean stop = false; 
 public static void main( String args[] ) throws Exception { 
 Example2 thread = new Example2(); 
 System.out.println( "Starting thread..." ); 
 thread.start(); 
 Thread.sleep( 3000 ); 
 System.out.println( "Asking thread to stop..." ); 
 
 thread.stop = true; 
 Thread.sleep( 3000 ); 
 System.out.println( "Stopping application..." ); 
 //System.exit( 0 ); 
 } 
 
 public void run() { 
  while ( !stop ) { 
  System.out.println( "Thread is running..." ); 
  long time = System.currentTimeMillis(); 
  while ( (System.currentTimeMillis()-time < 1000) && (!stop) ) { 
  } 
  } 
 System.out.println( "Thread exiting under request..." ); 
 } 
 } 
Listing Bを実行するコードは以下のように出力されます。
Starting thread…
Thread is running…
Thread is running…
Thread is running…
Asking thread to stop…
Thread exiting under request…
Stopingアプリ…
   この方法はいくつかのコードを要求しているが、実現は難しくない。同時に、スレッドの機会を与えて、必要なクリーンアップ作業を行います。これは任意のマルチスレッドアプリケーションでは絶対必要です。共有変数をvolatileタイプと定義したり、同期ブロック/メソッドにすべてアクセスすることを確認してください。
今まではすべて順調です。しかし、スレッドがいくつかのイベントを待ってブロックされると、何が起こるか?もちろん、スレッドがブロックされていると、共有変数を確認できなくなり、停止できなくなります。これは多くの場合、例えばObject.wait()、ServerSockett.accept()とDatagram Sockett.receive()を呼び出した場合、ここではいくつかしか挙げられません。
彼らはスレッドを永久にブロックすることができます。タイムアウトが発生しても、オーバータイムが満了する前に待ち続けるのは不適切であるため、スレッドがブロックされた状態を早期に終了させるための仕組みが必要である。
幸いではないです。このような仕組みはすべての場合に適用されますが、場合によっては特定の技術が使えます。次のステップで、最も一般的な例を説明します。
Thread.interrupt()を使ってスレッドを中断します。
  Listing Aに記述されているように、Thread.interrupt()方法は、実行中のスレッドを中断しない。この方法は実際には、スレッドがブロックされているときに割り込み信号を送ることで、スレッドがブロック状態から抜けることができる。より正確には、スレッドがObject.wait、Thread.jun、Thread.sleepの3つの方法のうちの一つによってブロックされると、中断異常が受信され、早期にブロックされた状態が終了する。
    したがって、スレッドが上記のようないくつかの方法でブロックされている場合、共有変数を設定し、interrupt()を呼び出します。スレッドがブロックされていない場合は、interruptを起動しても機能しません。そうでないと、スレッドに異常が発生します。いずれの場合も、最後のスレッドは共有変数をチェックして停止します。Listing Cの例は、この技術を説明する。
Listing C

 class Example3 extends Thread { 
 volatile boolean stop = false; 
 public static void main( String args[] ) throws Exception { 
 Example3 thread = new Example3(); 
 System.out.println( "Starting thread..." ); 
 thread.start(); 
 Thread.sleep( 3000 ); 
 System.out.println( "Asking thread to stop..." ); 
 thread.stop = true;//      ,         
 thread.interrupt(); 
 Thread.sleep( 3000 ); 
 System.out.println( "Stopping application..." ); 
 //System.exit( 0 ); 
 } 
 
 public void run() { 
  while ( !stop ) { 
  System.out.println( "Thread running..." ); 
  try { 
  Thread.sleep( 1000 ); 
  } catch ( InterruptedException e ) { 
  System.out.println( "Thread interrupted..." ); 
  } 
  } 
 System.out.println( "Thread exiting under request..." ); 
 } 
 } 
Listing C中のThread.interrupt()が呼出されると、スレッドに異常が発生し、閉塞状態から脱出し、停止すべきであると判断される。以上のコードを実行すると次の出力が得られます。
Starting thread…
Thread running…
Thread running…
Thread running…
Asking thread to stop…
Thread interrupted…
Thread exiting under request…
Stopingアプリ…
割込みI/O操作
    しかし、スレッドがI/O操作でブロックされるとどうなりますか?I/O動作は、スレッドをかなり長い間ブロックすることができ、特にネットワークアプリケーションに関連する場合。例えば、サーバは、要求を待つ必要があるかもしれないし、または、ネットワークアプリケーションは、リモートホストの応答を待つ必要があるかもしれない。
チャンネル(Java 1.4で導入された新しいI/O API)を使用していると、ブロックされたスレッドはCloosedByInterrupt Exceptionの異常を受信します。このような場合、そのコードの論理は第三例と同じで、異常な違いだけです。
しかし、Java 1.0を使用している可能性があります。以前から存在していた伝統的なI/Oは、より多くの仕事を求めています。このようにすると、Thread.interrupt()が機能しなくなります。スレッドはブロックされた状態から退出しません。Listing Dはこの挙動を説明した。interrupt()が起動されても、スレッドはブロックされた状態から退出しません。
Listing D

 import java.io.*; 
 class Example4 extends Thread { 
 public static void main( String args[] ) throws Exception { 
  Example4 thread = new Example4(); 
 System.out.println( "Starting thread..." ); 
 thread.start(); 
 Thread.sleep( 3000 ); 
 System.out.println( "Interrupting thread..." ); 
 thread.interrupt(); 
 Thread.sleep( 3000 ); 
 System.out.println( "Stopping application..." ); 
 //System.exit( 0 ); 
 } 
 
 public void run() { 
 ServerSocket socket; 
  try { 
  socket = new ServerSocket(7856); 
  } catch ( IOException e ) { 
  System.out.println( "Could not create the socket..." ); 
  return; 
  } 
  while ( true ) { 
  System.out.println( "Waiting for connection..." ); 
  try { 
  Socket sock = socket.accept(); 
  } catch ( IOException e ) { 
  System.out.println( "accept() failed or interrupted..." ); 
  } 
  } 
 } 
 } 
 幸いにも、Javaプラットフォームはこのような状況のために、スレッドをブロックするソケットのCose()を呼び出す解決策を提供している。この場合、スレッドがI/O操作でブロックされると、このスレッドはSocketException異常を受信し、これはinterrupt()方法を使用してInterrupt Exception異常を引き起こすと非常に似ている。
唯一の説明としては、socketの引用が必要であり、このようなclose()方法だけが呼び出されます。これは、socketオブジェクトが共有されなければならないことを意味する。Listing Eはこの状況を述べている。運転ロジックは以前の例と同じです。
Listing E

 import java.net.*; 
 import java.io.*; 
 class Example5 extends Thread { 
 volatile boolean stop = false; 
 volatile ServerSocket socket; 
 public static void main( String args[] ) throws Exception { 
  Example5 thread = new Example5(); 
 System.out.println( "Starting thread..." ); 
 thread.start(); 
 Thread.sleep( 3000 ); 
 System.out.println( "Asking thread to stop..." ); 
 thread.stop = true; 
 thread.socket.close(); 
 Thread.sleep( 3000 ); 
 System.out.println( "Stopping application..." ); 
 //System.exit( 0 ); 
 } 
 public void run() { 
  try { 
  socket = new ServerSocket(7856); 
  } catch ( IOException e ) { 
  System.out.println( "Could not create the socket..." ); 
  return; 
  } 
  while ( !stop ) { 
  System.out.println( "Waiting for connection..." ); 
  try { 
  Socket sock = socket.accept(); 
  } catch ( IOException e ) { 
  System.out.println( "accept() failed or interrupted..." ); 
  } 
  } 
 System.out.println( "Thread exiting under request..." ); 
 } 
 } 
Listing Eのコードを実行した後の出力は以下の通りです。

Starting thread...
Waiting for connection...
Asking thread to stop...
accept() failed or interrupted...
Thread exiting under request...
Stopping application...
マルチスレッドは強力なツールであるが,これは一連の難題を呈している。一つはどうやって実行中のスレッドを中断するかです。適切に実現すれば、上述の技術を使用してスレッドを中断することは、Javaプラットフォーム上ですでに提供されている埋め込み動作を使用するよりも簡単である。
以上は小编で绍介したJava interruptの使い方に注意して、皆さんに助けてほしいです。もし何か疑问があれば、メッセージをください。小编はすぐに返事します。ここでも私たちのサイトを応援してくれてありがとうございます。