Javaのinterruptを試す
スレッドのキャンセルについて勉強します。
- 作者: ケンアーノルド,デビッドホームズ,ジェームズゴスリン,Ken Arnold,David Holmes,James Gosling,柴田芳樹
- 出版社/メーカー: 東京電機大学出版局
- 発売日: 2014/05/10
- メディア: 単行本
- この商品を含むブログ (4件) を見る
スレッドへの割り込みに関するメソッドは以下の3つがあります。
- Thread.interrupt()
- Thread.interrupted()
- Thread.isInterrupted()
interruptは、スレッドへの割込みを送ります。isInterruptedはスレッドが割り込まれたかどうかを検査します。interruptedは、staticメソッドであり、カレントスレッドが割り込まれたかどうかを検査し、その後、そのスレッドの「割り込まれた」状態をクリアーします。スレッドの割り込まれた状態は、割り込まれたスレッド自身だけがクリアーできます。
スレッドへの割り込みは、通常はスレッドが行っている事に対して影響したりしませんが、sleepやwait等のいくつかのメソッドは、
InterruptedException
をスローします。もし、スレッドが割り込まれた時に、スレッドがこれらのメソッドの1つを実行していると、そのメソッドはInterruptedException
をスローします。
Thread.sleep() 中での interrupt()
public class Sample { public static void main(String[] args) throws InterruptedException { Thread task = new Thread(new MySleepTask()); task.start(); System.out.printf("[%s] :isInterrupted = %s\n", task.getName(), task.isInterrupted()); Thread.sleep(3000); task.interrupt(); System.out.printf("[%s] :isInterrupted = %s\n", task.getName(), task.isInterrupted()); } } class MySleepTask implements Runnable { @Override public void run() { try { System.out.printf("[%s] :%s\n", Thread.currentThread().getName(), "start!"); Thread.sleep(10000); System.out.printf("[%s] :%s\n", Thread.currentThread().getName(), "finish!"); } catch (InterruptedException e) { System.out.printf("[%s] :%s\n", Thread.currentThread().getName(), "interrupted!"); e.printStackTrace(); } } }
結果
interrupt()
発行後に isInterrupted()
がtrueになっていることが分かります。 sleep()
メソッド実行中に interrupt()
されると InterruptedException
が発生し、上記のサンプルコードでは、[Thread-0] :finish! となることなく、スレッドが終了していることが分かります。
[Thread-0] :isInterrupted = false [Thread-0] :start! [Thread-0] :isInterrupted = true [Thread-0] :interrupted! java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at sample_14_8.MySleepTask.run(Sample.java:26) at java.lang.Thread.run(Thread.java:748)
独自メソッド中での interrupt()
通常は interrupt()
されたとしても InterruptedException
は発生しないため、以下の独自実装では InterruptedException
は発生しません。
package sample_14_8; public class Sample { public static void main(String[] args) throws InterruptedException { Thread task = new Thread(new MyTask()); task.start(); System.out.printf("[%s] :(%s) isInterrupted = %s\n", task.getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), task.isInterrupted()); Thread.sleep(3000); System.out.printf("[%s] :(%s) %s\n", task.getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), "3000ms slept..."); task.interrupt(); Thread.sleep(3000); System.out.printf("[%s] :(%s) isInterrupted = %s\n", task.getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), task.isInterrupted()); } } class MyTask implements Runnable { @Override public void run() { System.out.printf("[%s] :(%s) %s\n", Thread.currentThread().getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), "start!"); doSomething(); System.out.printf("[%s] :(%s) isInterrupted = %s\n", Thread.currentThread().getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), Thread.currentThread().isInterrupted()); System.out.printf("[%s] :(%s) %s\n", Thread.currentThread().getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), "finish!"); } public void doSomething() { while (!Thread.interrupted()) { // 何らかの処理 } System.out.printf("[%s] :(%s) %s\n", Thread.currentThread().getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), "interrupted!"); } }
結果
Thread.interrupted()
は以下の仕様になっています。
現在のスレッドが割り込まれているかどうかを調べします。このメソッドによりスレッドの割込みステータスがクリアされます。つまり、このメソッドが続けて2回呼び出された場合、2回目の呼出しはfalseを返します(最初の呼出しが割込みステータスをクリアしたあとで、2番目の呼出しがそれを確認する前に現在のスレッドがもう一度割り込まれた場合を除く)。
よって上記の独自クラスの場合は、interrupt()
された時にtrueになるが、次に検査するときにはfalseになるので、ビジーループからは抜けているが、出力結果はfalseになっています。
[Thread-0] :(main) isInterrupted = false [Thread-0] :(run) start! [Thread-0] :(main) 3000ms slept... [Thread-0] :(doSomething) interrupted! [Thread-0] :(run) isInterrupted = false [Thread-0] :(run) finish! [Thread-0] :(main) isInterrupted = false