1. interrupt()方法介绍
interrupt()方法
interrupt()的作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),只会给线程设置一个中断标志,线程仍会继续运行。
本线程中断自己是被允许的;其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。
如果本线程是处于阻塞状态:调用线程的wait(),、join()、sleep()方法会让它进入阻塞状态。若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“中断状态”会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中
断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。
如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时;线程的中断标记会被设置为true,并且它会立即从选择操作中返回。
interrupted()方法
作用是测试当前线程 是否被中断(检查中断标志),返回一个boolean并清除中断状态,第二次再调用时中断状态已经被清除,将返回一个false。
isInterrupted()方法
作用是测试此线程 是否被中断(检查中断标志),返回一个boolean,不清除中断状态
2. interrupt示例
上面的介绍中有说,interrupt只能设置一个中断标记,并不能实际中断线程的运行。下面通过一个例子来说明这一点:
public class InterruptTest extends Thread {
public void run(){
for (int i = 0 ; i < 5; i++){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("愉快的玩耍" + i);
}
}
public static void main(String[] args){
InterruptTest test = new InterruptTest();
test.start();
test.interrupt();
System.out.println("线程是否被中断:"+ test.isInterrupted());
System.out.println("线程是否存活:" + test.isAlive());
}
}
运行结果如下:
从运行结果我们可以看出,线程在sleep()中被中断,中断标记被设置为true,并且抛出了InterruptedException异常,但是该线程依然在运行。因此interrupt()方法只会设置中断标志,并不会实际终止线程。
再来看一个例子,把上面的代码稍微做一点改动:
public static void main(String[] args){
InterruptTest test = new InterruptTest();
test.start();
test.interrupt();
System.out.println("线程是否被中断:"+ test.isInterrupted());
System.out.println("线程是否存活:" + test.isAlive());
System.out.println("调用interrupted():" + test.interrupted());
System.out.println("调用interrupted():" + test.interrupted());
}
运行结果:
前面我们讲过,interrupted()方法不仅可以返回中断标记,还能将中断标记设置为false,那第一次调用的结果为什么不是true呢?这是因为interrupted()方法返回和清除的是当前线程的中断标志,这段代码运行在main()中,那当前线程当然是主线程,所以返回清除的是主线程的中断标记。
3. 如何优雅的终止线程
interrupt()方法只能设置中断标记,那要真正终止线程的运行,需要使用什么方法呢?首先应该明确的是Thread中的stop()和suspend()方法,由于固有的不安全性,已经建议不再使用!
1. 终止阻塞的线程
终止阻塞的线程可以在外部调用interrupt()方法使线程产生interruptedException,在代码内部捕获该异常退出运行,示例如下:
@Override
public void run() {
try {
while (true) {
// 执行任务...
}
} catch (InterruptedException ie) {
// 由于产生InterruptedException异常,退出while(true)循环,线程终止!
}
}
如果我们将try/catch放在while循环内部的话,就需要手动添加break来中断,负责while循环不会通知。
2. 终止正在运行的线程
终止正在运行的线程有两种方式,一种是通过判断中断标记,另一个是额外添加标记,这里推荐使用第一种,来看一下示例:
@Override
public void run() {
while (!isInterrupted()) {
// 执行任务...
}
}
综合上面两种线程的状态,我们可以得出通用的终止方式:
@Override
public void run() {
try {
// 1. isInterrupted()保证,只要中断标记为true就终止线程。
while (!isInterrupted()) {
// 执行任务...
}
} catch (InterruptedException ie) {
// 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。
}
}