http://www.cnblogs.com/biGpython/archive/2012/03/05/2380858.htmlhtml
http://blog.csdn.net/hudashi/article/details/6958550java
http://hainiubl.com/topics/29#为什么调用wait方法有可能抛出InterruptedException异常python
《Java并发编程的艺术》是这么写的:编程
从Java的API中能够看出,许多声明抛出InterruptedException的方法(例如Thread.sleep(long millis)方法)这些方法在抛出InterruptedException以前,Java虚拟机会先将该线程的中断标识位清除(即设置为false),而后抛出InterruptedException,此时调用isInterrupted()方法将会返回false。并发
这是什么意思呢?ide
如下面的 InterruptJoinTest 类代码为例说明(详细代码见InterruptJoinTest 类代码)。main线程先启动了t2线程,而后调用t2.interrupt()方法对t2线程进行中断,this
t2.start();spa
t2.interrupt();.net
回顾下JDK中的源码以下线程
注意红框中的注释,调用t2.interrupt()方法就是将t2的中断标识位进行了置位(设置为true)。
注意这里,调用t2.interrupt()方法对t2线程进行中断也就是对t2的中断标识位进行了置位,置位后,t2的中断标识位为true,而后t2线程会抛出InterruptedException异常。再回过头来看《Java并发编程的艺术》中的话:
在抛出InterruptedException以前,Java虚拟机会先将该线程的中断标识位清除(即设置为false),而后抛出InterruptedException
也就是说:调用t2.interrupt()方法将中断标识位设置为true;而后t2线程要抛出InterruptedException异常,t2抛出InterruptedException异常以前Java虚拟机又会将t2的中断标识位设置为false(即将t2的中断标识位清除)。那么意味着线程t2的中断标识位被设置为true的时间其实至关短暂,立刻随着InterruptedException异常的抛出又被重置为了false。
以上这些说明,是为了更好的理解下面的代码示例。
研究InterruptedException类代码的执行结果,会有更深的体会。
public class InterruptJoinTest { public static void main(String... args) { T1 t1 = new T1(); T2 t2 = new T2(t1); t1.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t2.start(); t2.interrupt(); } } class T1 extends Thread { public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "======" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class T2 extends Thread { private T1 t; public T2(T1 t) { this.t = t; } public void run() { try { t.join(); System.out.println(Thread.currentThread().getName() + "######"); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println(Thread.currentThread().getName() + "$$$$$$$$$$$$$$$" + Thread.currentThread().isInterrupted()); } } }
Thread-0======0
Thread-0======1
Thread-0======2
Thread-0======3
Thread-0======4
Thread-1######
Thread-0======0
Thread-1$$$$$$$$$$$$$$$false
Thread-0======1
Thread-0======2
Thread-0======3
Thread-0======4
t2线程中调用了t1.join(),因此t2线程进入了对象t1的等待队列(即对象t1的wait set),t2线程要等待t1线程执行完毕才能继续。此时t2线程在不断地检查自身中断状态的值(底层来实现)。
主线程即main线程中调用了t2.interrupt(),将t2线程的中断状态位设置为true。同时t2线程不断地检查自身中断状态的值,发现了置位(中断状态位被设置为true),因此抛出InterruptedException异常,进行了复位(设置为false),而后t2线程进入了catch异常处理代码块。
t1线程没受什么影响,继续本身的运行。
import java.util.concurrent.TimeUnit; public class InterruptWaitTest { volatile static boolean b = true; public static void main(String... strings) throws InterruptedException{ final byte[] lock = new byte[0]; Thread t = new Thread(new Runnable() { public void run() { while (b) { } synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " in waiting!!"); lock.wait(); System.out.println("@$%^^$^&*#E%^&*("); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println(Thread.currentThread().getName() + " end waiting!!"); System.out.println(Thread.currentThread().isInterrupted()); } } } }, "t"); t.interrupt(); TimeUnit.SECONDS.sleep(1); System.out.println("########## " + t.isInterrupted()); t.start(); // t.interrupt(); // System.out.println("@@@@@@@@@@@@@ " + t.isInterrupted()); // b = false; try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
########## false
线程t还没运行,主线程即main线程中就调用了t.interrupt()方法,此时打印线程t的中断状态位,发现线程t的中断状态位并未被置位。因此线程t没有受interrupt()方法的任何影响。启动线程t后直接执行t里面的run()方法。
import java.util.concurrent.TimeUnit; public class InterruptWaitTest { volatile static boolean b = true; public static void main(String... strings) throws InterruptedException{ final byte[] lock = new byte[0]; Thread t = new Thread(new Runnable() { public void run() { while (b) { } synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " in waiting!!"); lock.wait(); System.out.println("@$%^^$^&*#E%^&*("); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println(Thread.currentThread().getName() + " end waiting!!"); System.out.println(Thread.currentThread().isInterrupted()); } } } }, "t"); // t.interrupt(); // TimeUnit.SECONDS.sleep(1); // System.out.println("########## " + t.isInterrupted()); t.start(); t.interrupt(); System.out.println("@@@@@@@@@@@@@ " + t.isInterrupted()); b = false; TimeUnit.SECONDS.sleep(1); } }
@@@@@@@@@@@@@ true
t in waiting!!
t end waiting!!
false
线程t在进入对象lock的等待队列以前,先在主线程即main线程中被调用interrupt()方法。t.interrupt()方法调用完,线程t的中断标识位已经被设置为true。
由于b为true,线程t在执行while空方法,不会去检查中断状态。
b变为false,线程t终于执行到lock.wait(),线程t进入了lock的等待队列即wait set。线程t不断循环检查本身的中断标识位,发现中断标识位已经为true,立刻会抛出 InterruptedException,进入catch异常处理代码块。
线程t若是在启动前调用t.interrupt()方法是不起做用的。
线程t启动后,调用t.interrupt()方法,在线程t进入某个对象的wait set后线程t会不断检查本身的中断标识位状态,若发现中断标识位状态已被设置为true,线程t就会抛出InterruptedException异常。
注意,只有线程t进入某个对象的wait set,线程t才会开始不断循环检查自身的中断标识位状态。不然即便线程t的中断标识位被设置为true,线程t不检查中断标识位,也不会抛出InterruptedException异常。
import java.util.concurrent.TimeUnit; public class InterruptSleepTest { public static void main(String[] args) throws Exception { // sleepThread不停的尝试睡眠 Thread sleepThread = new Thread(new SleepRunner(), "SleepThread"); sleepThread.setDaemon(true); // busyThread不停的运行 Thread busyThread = new Thread(new BusyRunner(), "BusyThread"); busyThread.setDaemon(true); sleepThread.start(); busyThread.start(); // 休眠5秒,让sleepThread和busyThread充分运行 TimeUnit.SECONDS.sleep(5); sleepThread.interrupt(); busyThread.interrupt(); System.out.println("SleepThread interrupted is " + sleepThread.isInterrupted()); System.out.println("BusyThread interrupted is " + busyThread.isInterrupted()); // 防止sleepThread和busyThread马上退出 TimeUnit.SECONDS.sleep(2); } static class SleepRunner implements Runnable { @Override public void run() { while (true) { // SleepUtils.second(10); try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println("!@#$%^&*(!@#$%^&*(!@#$%^&*"); } } } } static class BusyRunner implements Runnable { @Override public void run() { while (true) { } } } }
!@#$%^&*(!@#$%^&*(!@#$%^&*
SleepThread interrupted is false
BusyThread interrupted is true
sleepThread.interrupt();
SleepRunner进行中断,由于SleepRunner正在进行sleep,方法内部会不断检查中断状态的值,检测到中断状态已经被置位(设置为true),那么就会抛出InterruptedException异常,而且将中断状态复位。因此看到的结果是跳进了catch异常处理代码块,且由于被复位,因此中断状态位是false。
busyThread.interrupt();
BusyRunner进行中断,由于BusyRunner没有sleep、wait、join,不会去检查中断状态,因此线程A不会抛出 InterruptedException,而会一直执行着本身的操做。这样interrupt()置位一直没有清除,因此中断状态位仍是true。
程序执行时,最后停顿2秒后终止,为何BusyRunner对应的线程没有一直执行呢?不是while(true)吗?由于 BusyRunner 是Daemon线程。main线程执行完毕后,JVM中就没有非Daemon线程了,因此JVM就退出了。线程 BusyRunner 就跟着一块儿结束了。
线程t处于如下三种状况下,
线程t由于调用某对象的wait()方法进入某对象的wait set;
线程t由于调用其余线程的join()进入其余线程(对象)的wait set;
线程t由于调用t.sleep()自身进入超时等待状态。
实际上这三种状况下线程t都处于wait set。
线程t在这三种状态下会不断循环检查自身的中断标识位,此时若是有线程调用t.interrupt()方法,会将线程t的中断标识位设置为true,那么线程t将接收到一个中断异常(InterruptedException),而后线程t的中断标识位会被复位为false,再而后线程t会进入catch异常处理代码块。
通过以上步骤,线程将从wait set中跳出。