起因
今天上午室友问了我一个关于线程的问题,问我为啥输出的C是true,D是false,我想了好一会没有反应过来。代码是这样子的:
public class InterrupTest implements Runnable{ public void run(){ try { while (true){ Boolean a=Thread.currentThread().isInterrupted(); // System.out.println("Threadname = "+Thread.currentThread().getName()); System.out.println("in run()-about to sleep for 20s------------------"+a); Thread.sleep(20000); System.out.println("in run()- woke up"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); Boolean c=Thread.interrupted(); Boolean d=Thread.interrupted(); System.out.println("c="+c); System.out.println("d="+d); } } public static void main(String[] args){ InterrupTest si=new InterrupTest(); Thread t=new Thread(si); t.start(); try { Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("in main() - interrupting other thread"); t.interrupt(); System.out.println("in main() - leaving"); } }
之前没注意过Thread.interrupt(),Thread.interrupted()的区别,于是看了一下源码,百了一下度。
public void interrupt() { if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0();//native方法 }
然后是interrupted()
public static boolean interrupted() { return currentThread().isInterrupted(true); }
//currentThread().isInterrupted() private native boolean isInterrupted(boolean ClearInterrupted);
原来interrupt()方法并没有直接中断一个线程,在java中并不是直接将进程终止(当然也有stop()方法,但是已经被弃用),而是对进程设置一个中断标志位,至于进程什么时候中断,需要在进程内部自己实现。具体的说:
*,如果一个线程处于了阻塞状态(如线程调用了thread.sleep、thread.join、thread.wait、1.5中的condition.await、以及可中断的通道上的 I/O 操作方法后可进入阻塞状态),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法(sleep、join、wait、1.5中的condition.await及可中断的通道上的 I/O 操作方法)调用处抛出InterruptedException异常, *,如果线程处于正常活动状态,那么会将该线程中的中断标志设置为true,仅此而已, 被设置中断标志的线程将继续正常执行,不受影响。 interrupt()并不能真正中断线程,需要被调用的线程自己进行配合才行。一个线程如果有被中断的需求,那么就可以这样做: *,在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志,就自行停止线程 *,在调用阻塞方法时正常处理InterruptException异常 作者:tracy_668 链接:https://www.jianshu.com/p/e2b22c6bcd22 来源:简书
再说interrupted(),它的作用没有中断的意思,而是检查线程的中断标志,如果有就返回true,并且将清除标志位,如果没有就返回false,所以这也就解释了为啥上面的CD不一样了。
再到isInterrupted()
public boolean isInterrupted() { return isInterrupted(false); }
可以看到后面跟的参数是false,也就是说它和interrupted()的区别是它是实例方法,不清空标志位,而interrupted()是静态方法且清空标志位。
拓展
Java进程的六个状态,看到Thread.getState(),再往下一层有:
public static State toThreadState(int var0) { if ((var0 & 4) != 0) { return State.RUNNABLE; } else if ((var0 & 1024) != 0) { return State.BLOCKED; } else if ((var0 & 16) != 0) { return State.WAITING; } else if ((var0 & 32) != 0) { return State.TIMED_WAITING; } else if ((var0 & 2) != 0) { return State.TERMINATED; } else { return (var0 & 1) == 0 ? State.NEW : State.RUNNABLE; } }
有六种状态。
1,NEW,TERMINATE
线程的NEW状态表示还未调用start方法,还未真正启动。线程的TERMINATE状态表示线程已经终止。这两个状态下调用中断方法来中断线程,所以并不会设置线程的中断标识位,什么事也不会发生。
2,RUNNABLE
表示运行状态,但是这并不代表所有的Runnable线程都获得了CPU的运行,一定的时间段内只有一个线程占用着CPU,此时发起中断操作也不对线程状态产生影响。
3,BLOCKED
即阻塞,线程由于竞争某个对象的锁失败而被挂在了该对象的阻塞队列上了,此时发起中断操作也不对线程状态产生影响。
4,WAIT,TIMED_WAIT
两者本质上是同一种状态,不过TIMED_WAITING在等待一段时间后会自动释放自己,而WAITING则是无限期等待,需要其他线程调用notify方法释放自己。但是两者都是由于线程在运行的过程中由于缺少某些条件而被挂起在某个对象的等待队列上。当这些线程遇到中断操作的时候,会抛出一个InterruptedException异常,并清空中断标志位。