线程中断
前言
一直对java线程的中断有点模糊的感觉,决心要弄清楚。
interrupted,isInterrupted,interrupt
Thread.interrupted();//清除中断标志,并返回清除前的值
Thread.currentThread().isInterrupted();//判断中断标志
Thread.currentThread().interrupt();//设置中断为true
我是这样理解的 线程中断标志默认 flag=false
interrupt方法把他改为true
isInterrupted方法返回flag,true代表中断,false代表未被中断
interrupted返回flag,并且重置flag=false
测试interrupted
由于interrupted最复杂,着重于测试这个方法,代码如下
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while(true){
}
}
});
t.start();
System.out.println("1:"+t.isInterrupted());
t.interrupt();//中断
System.out.println("2:"+t.isInterrupted());
System.out.println("3:"+t.interrupted());
System.out.println("4:"+t.isInterrupted());
如果按照我们之前的分析,那么输出结果应该如下所示
1:false
2:true
3:true
4:false
可是实际的结果如下
1:false
2:true
3:false
4:true
从这个结果可以看出来线程t一直是中断的状态
那么 t.interrupted() 这行代码为什么没有重置 t 线程的flag=false呢?
跟进interrupted源码看看
public static boolean interrupted() {
//原因在这里 currentThread()!=t
return currentThread().isInterrupted(true);
}
下面我们来确定 currentThread()!=t
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while(true){
}
}
});
t.start();
System.out.println("t:"+t);
System.out.println("main:"+Thread.currentThread());
System.out.println("1:"+t.isInterrupted());
t.interrupt();//中断
System.out.println("2:"+t.isInterrupted());
System.out.println("3:"+t.interrupted());
System.out.println("4:"+t.isInterrupted());
我们在interrupted源码里打个断点,debug执行,选中currentThread()后右键选择Evaluate Expression执行的result=Thread[main,5,main]
控制台输出结果是
t:Thread[Thread-0,5,main]
main:Thread[main,5,main]
1:false
2:true
3:false
4:true
问题已经定位清楚了,下面我们来写一个正确的例子来证明interrupted确实有清除中断标志,并返回清除前的值这两个功能。
public static void main(String[] args) throws InterruptedException {
System.out.println("1:"+Thread.currentThread().isInterrupted());
Thread.currentThread().interrupt();
System.out.println("2:"+Thread.currentThread().isInterrupted());
System.out.println("3:"+Thread.interrupted());
System.out.println("4:"+Thread.currentThread().isInterrupted());
}
输出,可以看出来interrupted确实生效了
1:false
2:true
3:true
4:false
如何优雅的停止线程
方案一:volatile
优点:代码简单
缺点:停止不及时
代码如下:
我们的本意是1s后停止线程,可是却等到10s后才停止。
private static volatile boolean flag=true;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
while(flag){
System.out.println("run");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
Thread.sleep(1000);
flag = false;
}
方案二:利用中断
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
//flag==false
while(!Thread.currentThread().isInterrupted()){
System.out.println("run");
try {
Thread.sleep(10000);//发现中断标志flag = true,重置flag = false,响应中断进入catch
} catch (InterruptedException e) {
System.out.println("catch:"+Thread.currentThread().isInterrupted());//catch:false
Thread.currentThread().interrupt();//再次中断,即可立即退出线程
}
}
}
});
t.start();
Thread.sleep(1000);
t.interrupt();//flag = true
}
个人不喜欢interrupted这个操作,我也尽量避免书写一些一个函数干多个事情的的代码。