这一篇我们说说java线程thread的interrupt中断机制。
中断线程
线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。它并不像stop方法那样会中断一个正在运行的线程。
判断线程是否被中断
判断某个线程是否已被发送过中断请求,请使用thread.currentthread().isinterrupted()方法(因为它将线程中断标示位设置为true后,不会立刻清除中断标示位,即不会将中断标设置为false),而不要使用thread.interrupted()(该方法调用后会将中断标示位清除,即重新设置为false)方法来判断,下面是线程在循环中时的中断方式:
1
2
3
|
while (!thread.currentthread().isinterrupted() && more work to do ){
do more work
}
|
interrupt之中断状态标记
interrupt中断机制中有如下方法:
- thread.interrupt(),设置当前中断标记为true(类似属性的set方法)
- thread.isinterrupted(),检测当前的中断标记(类似属性的get方法)
- thread.interrupted(),检测当前的中断标记,然后重置中断标记为false(类似属性的get方法+set方法)
因此interrupt中断机制并不是真正的将当前线程中断,而是一个中断标记的变化。我们先用例子来测试一下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
public class interrupttest {
//这里用来打印消耗的时间
private static long time = 0 ;
private static void resettime(){
time = system.currenttimemillis();
}
private static void printcontent(string content){
system.out.println(content + " 时间:" + (system.currenttimemillis() - time));
}
public static void main(string[] args) {
test1();
}
private static void test1(){
thread1 thread1 = new thread1();
thread1.start();
//延时3秒后interrupt中断
try {
thread.sleep( 3000 );
} catch (interruptedexception e) {
e.printstacktrace();
}
thread1.interrupt();
printcontent( "执行中断" );
}
private static class thread1 extends thread{
@override public void run() {
resettime();
int num = 0 ;
while ( true ){
if (isinterrupted()){
printcontent( "当前线程 isinterrupted" );
break ;
}
num++;
if (num % 100 == 0 ){
printcontent( "num : " + num);
}
}
}
}
}
|
以上代码是开启一个thread1线程,在thread1线程的while循环中不断对num加1,每到100的倍数打印一次(防止打印太快)。然后主线程在sleep了3000毫秒后,调用thread1线程的interrupt方法。那么我们看看输出结果:
intterupt中断
可以看到,在耗时3000毫秒左右,也就是主线程sleep之后执行thread1.interrupt();后,thread1线程停止了,而thread1线程的停止是因为while循环中的isinterrupted方法返回了true,所以break退出了while循环,也就是说interrupt和isinterrupted在这里起到的作用就相当于setxx和getxx的作用,维护着一个boolean变量。
interrupt之中断异常处理
当然interrupt机制并不仅仅是一个中断状态位的变化和检测,它还可以进行中断异常的处理。我们知道thread.sleep()方法需要捕获中断异常,那接下来我们往其中添加一个sleep延时试试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
while ( true ){
if (isinterrupted()){
printcontent( "当前线程 isinterrupted" );
break ;
}
num++;
//sleep一下
try {
thread.sleep( 1 );
} catch (interruptedexception e) {
e.printstacktrace();
}
if (num % 100 == 0 ){
printcontent( "num : " + num);
}
}
|
我们再看看输出结果:
intterupt中断
这里我们会发现,sleep睡眠之后,输出的num值明显小了好多(没睡眠时num都达到10亿的大小了,看来cpu执行简单运算还是非常快的),哈哈,不过这不是重点,重点是是看到输出了一个异常,还有就是输出异常后,isinterrupted输出返回false,thread1线程又继续执行下去了,并没有退出while循环。那么这是为什么呢?我们只是加了一个sleep睡眠而已。
如果thread1线程中有执行需要捕获interruptedexception异常的操作,比如thread的sleep,join方法,object的wait,condition的await等,它是强制需要捕获interruptedexception异常的,那么当thread1.interrupt方法调用之后,它会给thread1线程抛出一个interruptedexception异常,那么在while循环中,就能捕获到这个异常然后这个异常抛出之后,又会马上将线程中断标识重置为false,因此在下次的while循环中判断isinterrupted时,它是false,也就不会break,然后while循环会一直执行下去。
因此interrupt()方法会根据thread线程中的run方法里是否有必须捕获interruptedexception异常的代码,而做出不同操作:
- 如果没有必须捕获interruptedexception异常的代码(比如thread.sleep()),则isinterrupted()会返回true,此时可以在isinterrupted的判断中处理中断变化。
- 如果有必须捕获interruptedexception异常的代码(比如thread.sleep()),则会抛出interruptedexception异常,并进行捕获,同时重置isinterrupted为false,此时得在异常捕获中处理中断变化。
interrupt的应用场景
通常interrupt适用于在线程执行中的循环标记判断,例如
1
2
3
|
while (!isinterrupted()){
...
}
|
但是如果在本次循环中出现阻塞了,那么线程就无法判断下次的isinterrupted标记,那么即便调用了interrupt()方法也无法退出循环,也就无法退出线程。例如
1
2
3
4
5
6
|
while (!isinterrupted()){
...
while ( true ){
//线程卡在这里了,则无法响应interrupte机制了
}
}
|
这样的话,interrupt就没辙了,线程会一直执行下去,不会被中断停止。
测试例子查看 我的github--javatest
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://www.jianshu.com/p/7f1071293a18