在讲解中断线程之前,需要了解一下三个函数的具体作用
1. interrupt(): interrupt的字面意思就是中断的意思,所以对不太了解Java多线程编程的同学来说,很容易误解直接调用该函数实现线程中断,其实这个函数的真正含义并非如此,它并不能马上停止线程的执行。线程调用此方法仅仅是将该线程的中断标志位设为true(默认为false),所以总的来说该函数的主要作用就是产生中断信号,设置中断标志。当程序检测到该线程的中断标志为true,采取何种操作,不管是中断还是继续运行,都有编码的人自己实现。
2. interrupted():检测当前线程是否为中断状态,该方法具有清除中断标志位为false的功能,即执行完该方法,线程的中断标志位会被置为false。查看该方法的 定义public static boolean interrupted()可知该方法为一个静态方法。
3. isInterrupted(): 此方法与interrupted的大体功能类似,可以测试线程Thread对象是否是中断状态,但有一点不同就是该方法不能清除中断状态标志。该方法的声明如下public boolean isInterrupted(),可以看到此方法不是一个静态方法。
了解了上述三个函数的作用,可以用如下的方法来完成线程的中断了。在线程执行或者处于阻塞状态时,检测中断标志位,如果标志位为true,抛出异常执行中断操作。在实现过程中对于处于执行状态和阻塞状态的线程其实是不同的,对于处于执行状态的线程,在检测到中断标志为true时,需要手动抛出InterruptedException,而处于阻塞状态的sleep(),wait()和join()则不需要,当检测到中断标志为true,会自动抛出InterruptedException。下面的两个例子分别展示了这两种情况。
执行状态的线程中断:
public class MyThread extends Thread{
@Override
public void run() {
try{
for(int i=0; i<50000; i++){
if(Thread.interrupted()){
throw new InterruptedException(); //如果中断标志为true,抛出异常
}
System.out.println("i=" + (i+1));
}
} catch (InterruptedException e) {
System.out.println("线程已被中断!");
System.out.println("the signal of interrupted: "+Thread.interrupted()); //interrupted()方法的清除中断标志位功能检测
e.printStackTrace();
}
}
}
<pre name="code" class="java">public class Run {
public static void main(String args[]){
try{
MyThread thread = new MyThread();
thread.start(); //启动线程
Thread.sleep(100);
thread.interrupt(); //产生中断信号
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
}
}
上述代码的执行结果为:
可以看到正在执行自增操作的线程被中断,还可以观察到interrupted()方法会清除中断标志为false。
处于sleep()状态的线程中断:
public class MyThread extends Thread{
@Override
public void run() {
try{
System.out.println("run begin");
Thread.sleep(20000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("线程已被中断!");
System.out.println("the signal of interrupted: "+Thread.interrupted());
e.printStackTrace();
}
}
}
public class Run {
public static void main(String args[]){
try{
MyThread thread = new MyThread();
thread.start();
Thread.sleep(100);
thread.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
}
}
上述代码的执行结果如下图所示:
可以看到在阻塞状态(sleep,wait,join)的线程的中断实现,并不需要手动抛出异常,线程会自动抛出异常。并且在抛出异常的同时,还会将中断标志位置为false。但并不是所有的阻塞状态都可以自动抛出InterruptedException,像某些I/O操作或者内部锁操作,但是这些阻塞状态又会抛出自己特殊的异常,用这些异常同样可以实现中断。