关于interrupt(),interrupted(),isInterrupted()用法分析
我想代码是非常容易解释这个问题的了。下文会给出总结。
直接来一段小代码吧:
public class Interrupt {
public static void main(String[] args) {
Thread t = new Thread(new Worker());
t.start();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.interrupt();
System.out.println("Main thread stopped.");
}
public static class Worker implements Runnable {
public void run() {
System.out.println("Worker started.");
boolean f; // 用于检测interrupted()第一次返回值
int i = 0;
Thread c = Thread.currentThread();
System.out.println("while之前线程中断状态isInterrupted():" + c.isInterrupted());
while (!(f = Thread.interrupted())) {// 判断是否中断,如果中断,那么跳出并清除中断标志位
// 一旦检测到中断,interrupted()第一次返回true,就可以跳出循环,第二次以及以后都是返回false
System.out.println("while内,还没中断,interrupted()返回值为:" + f);
System.out.println(c.getName() + " " + i++ + " " + c.isInterrupted());
}
System.out.println("跳出循环即第一次中断interrupted()返回值:" + f);
System.out.println("while之后线程中断状态isInterrupted():" + c.isInterrupted()); // 为false,因为interrupt()会清除中断标志位,显示为未中断
System.out.println("第二次及以后的interrupted()返回值:" + Thread.interrupted());
c.interrupt();
System.out.println("再次中断后查询中断状态isInterrupted():" + c.isInterrupted());
System.out.println("Worker stopped.");
}
}
}
运行结果:
....................省略一些相同步骤
分析说明:
interrupt()是用于中断线程的,调用该方法的线程的状态将被置为"中断"状态。注意:线程中断仅仅是设置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。这里可以看到中断后该线程还在继续往下执行,并没有强制终止线程。
为什么主线程执行t.interrupt()后再调用isInterrupt()返回false??
因为这里调用interrupted()会清除中断标志位。
还有一种情况:如果线程在wait, sleep,join的时候受阻,调用了interrupt()方法,那么不仅会清除中断标志位,还会抛出InterruptedException异常。下文最后会给出这个例子。
来看看interrupted()和isInterrupted()实现
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);
这是一个native方法,看不到源码,但是注释说明,如果传入false,则不会清除中断标志位,如果传入true,则会清除中断标志位。
isInterrupted ()很老实,只查询中断标志位,不改变中断标志位。
==============================================================================
如果线程在wait, sleep,join的时候受阻,调用了interrupt()方法,那么不仅会清除中断标志位,还会抛出 InterruptedException异常。
那么再给出一个例子。
public class Interrupt {
public static void main(String[] args) throws Exception {
Thread t = new Thread(new Worker());
t.start();
Thread.sleep(100);
t.interrupt();
System.out.println("Main thread stopped.");
}
public static class Worker implements Runnable {
public void run() {
System.out.println("Worker started.");
try {
Thread.sleep(500); // 此时被interrupt()会抛出InterruptedException
} catch (InterruptedException e) {
Thread thread = Thread.currentThread();
System.out.println("再次中断之前isInterrupted():" + thread.isInterrupted());
System.out.println("再次中断之前interrupted():" + Thread.interrupted());
// 再次调用interrupt方法中断自己,将中断状态设置为“中断”
thread.interrupt();
System.out.println("再次interrupt()后isInterrupted():" + thread.isInterrupted());
System.out.println("再次interrupt()后第一次interrupted()返回:" + Thread.interrupted());// clear status
// interrupted()判断是否中断,还会清除中断标志位
System.out.println("interrupted()后此时再判断IsInterrupted: " + thread.isInterrupted());
System.out.println("---------After Interrupt Status Cleared----------");
System.out.println("再次interrupt()后第二次interrupted()返回: " + Thread.interrupted());
System.out.println("此时再判断IsInterrupted: " + thread.isInterrupted());
}
System.out.println("Worker stopped.");
}
}
}
运行结果:
总结:
interrupt()方法
如果不会中断sleep,wait,join方法或文档描述的其他情况,就不会抛InterruptException异常,就不会清除中断标志位,isInterrupt()返回true。
如果中断sleep,wait,join等,就会抛InterruptException异常,就会清除中断标志位,isInterrupt()返回false。
interrupted()方法
第一次使用返回true,并清除中断标志位,在此之后查询中断状态isInterrupt()都会返回false,刚刚第一个例子也看到了,利用 第一次返回的true可以跳出循环。第二次以及以后都是返回false。
isInterrupted()方法
仅仅查询中断标志位来判断是否发生中断并返回true或者false。
如果中断sleep,wait,join等,就会抛InterruptException异常,就会清除中断标志位,那么这种情况应该怎么处理呢?为了保证数据的一致性和完整性,我们需要用Thread.interrupt()方法再次中断自己,置上中断标志位。例子如下:
public class test {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread() {
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interruted!");
break;
}
try {
Thread.sleep(2000); // 睡眠时中断会清除中断标志位
} catch (InterruptedException e) {
// 如果少了下面这句,这个线程虽然在外面中断,但是只要中断睡眠中的进程
// 就会清除中断标志位,仍然处于无限循环,会竞争CPU资源
Thread.currentThread().interrupt(); // 再次中断置上中断标记
}
Thread.yield();
}
}
};
t1.start();
Thread.sleep(200);
t1.interrupt();
}
}
Thread.sleep()方法由于中断而抛出异常,此时,它会清除中断标记,如果不加处理,那么在下一次循环开始时,就无法捕获这个中断,故在异常处理中,再次设置中断标志位。
接下来给出官方文档说明:
interrupt
public void interrupt()
中断线程。
如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess
方法就会被调用,这可能抛出 SecurityException
。
如果线程在调用 Object
类的 wait()
、wait(long)
或 wait(long, int)
方法,或者该类的 join()
、join(long)
、join(long, int)
、sleep(long)
或 sleep(long, int)
方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException
。
如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException
。
如果该线程在一个 Selector
中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup
方法一样。
如果以前的条件都没有保存,则该线程的中断状态将被设置。
中断一个不处于活动状态的线程不需要任何作用。
抛出:
SecurityException
- 如果当前线程无法修改该线程
interrupted
public static boolean interrupted()
测试当前线程是否已经中断。线程的 中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。
返回:
如果当前线程已经中断,则返回 true
;否则返回 false
。
另请参见:
isInterrupted
public boolean isInterrupted()
测试线程是否已经中断。线程的 中断状态 不受该方法的影响。
线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。
返回:
如果该线程已经中断,则返回 true
;否则返回 false
。
另请参见:
==========================Talk is cheap, show me the code============================