线程中的中断标志位
一.与线程中断有关的3个方法:
interrupt():中断线程,改变其线程的中断标志位(仅仅只有一个通知的作用),但是否中断由自己线程判断决定。false——>true
isInterrupted():返回线程目前的中断标志位值
Thread.interrupted():返回线程目标的中断标志位,并将标志位复位 true——>false
Thread.interrupted()源码:
ClearInterrupted参数:true-中断标志位复位 false-不复位
二.线程中使用sleep,wait,join等方式会使线程阻塞,interrupt阻塞中的线程会抛出interruptedException异常,并将中断标志位复位
(true——>false)。
安全的中断线程:自定义标志+中断标志位监测
private static class TestThread extends Thread {
private volatile boolean on =true;
private long i = 0;
@Override
public void run() {
// TODO Auto-generated method stub
while(on && !Thread.currentThread().isInterrupted()){//未中断
try {
System.out.println("i="+i++);
//wait,sleep,join等阻塞
Thread.sleep(1000);
} catch (InterruptedException e) {//T——>F
// TODO Auto-generated catch block
//e.printStackTrace();
System.out.println("线程:"+Thread.currentThread().getName()+",异常中重新置位中断标志");
Thread.currentThread().interrupt();//F——>T
System.out.println("1-1:"+Thread.currentThread().isInterrupted());
}
}
System.out.println("1-2:on:"+on+"|中断标志位:"+Thread.currentThread().isInterrupted()+"|线程名称:"+Thread.currentThread().getName());
System.out.println("阻塞解除!");
}
public void cancel(){
on=false;
interrupt();//F ——>T
System.out.println("解除cancel中,thread.getName():"+getName());//运行的线程
//Thread.currentThread().interrupt();//中断的是主线程(即调用cancel方法的线程本身)
System.out.println("解除cancel中,Thread.currentThread:"+Thread.currentThread().getName());//调用cancel的线程(在此是main)
}
}
测试main类:
public static void main(String[] args) {
TestThread th=new TestThread();
th.start();
Thread.sleep(5000);
th.cancel();
}
疑问1:为什么要自定义标志+中断标志去判断?
如果只使用flag是不安全的取消操作,阻塞后,线程不会时刻去判断while中的条件,需要等待被唤醒(而interrupt后线程会立即响应)才会去检查条件是否满足。
中断的操作首先改变flag,再使用interrupt()
1.如果只使用flag去判断,出现interrupt()异常,未成功把中断标志置为true,也不能代表中断已经成功。
2.如果只使用!Thread.currentThread().isInterrupted(),假如在程序运行过程中,中断标志位因为异常而被置为true,也并不是正常的中断。
疑问2:为什么我写的中断程序没有中断呢?
1.线程中while条件的需要 自定义标志+中断标志位监测
2.抛出interruptedException异常后,中断标志位会复位,所以在catch代码块中要有重新置位
Thread.currentThread().interrupt();
注意:在主线程中调用
th.cancel();
cancel方法中System.out.println("Thread.currentThread:"+Thread.currentThread().getName());
Thread.currentThread()对象是主线程(main)--------调用th.cancel()代码的线程,而并不是th这个线程。
三.不可中断的阻塞,是不响应interrupte中断的,如何让其响应普通的中断?
java中不可中断的有IO通讯中的inputStream/outputStream的read/write方法,NIO中selector.select()等。
解决方式:在声明线程中,覆写interrupt()方法,首先关闭底层的套接字,再调用super.interrupt(),因为在关闭套接字的时候,会像interruptedException一样抛出一个异常,我们可以捕获这个异常来进行处理。