我们都知道线程被终止一般有两个原因:一是run()方法正常执行完毕而自然死亡;二是因为一个没有捕获的异常终止了run方法而异外死亡。
当一个线程在正常执行完毕之前被中断是一件很可怕的事情,会出现很多意想不到的事情,比如不能归还锁而造成死锁现象,stop()方法和destroy()方法就是因此而被废弃的。
在前一篇博客中,我们尝试了利用一些变量以指示目标线程应该停止运行来达到线程终止的目的。在Java的API中也有类似的方法,那就是interrupt()中断方法。
在Java的API中,除了interrupt()方法外,还提供了另外两个用于中断检测的方法,分别是isInterrupted()和interrupted()。
interrupt()
interrupt()是一个实例方法,该方法用于设置当前线程的对象的中断标识位。
在Java的API中,线程只能靠interrupt中断,而且不是立刻中断,是通过修改了被调用线程的中断状态来告知那个线程, 说它被中断了,线程会在一个合适的时候进行中断处理。
注意:每个线程都有一个boolean类型状态位用于标识当前线程对象是否是中断状态。
线程中断是一种协作机制,调用线程对象的interrupt方法并不一定就中断了正在运行的线程,它只是要求线程自己在合适的时间中断自己。
如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess方法就会被调用,这可能抛出SecurityException。
注意:checkAccess()方法用于判定当前运行的线程是否有权修改该线程如果不允许当前线程访问该线程,则会抛出SecurityException。
例如:
public class Test {
static int i = 0;
static class MyThread implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
while (!Thread.currentThread().isInterrupted() || i < 16) {
System.out.println(i++);
if (i == 9) {
Thread.currentThread().interrupt();
System.out.println("线程中断标识位:" + Thread.currentThread().isInterrupted());
}
}
}
}
public static void main(String[] args) {
new Thread(new MyThread()).start();
}
}
运行结果:
上述例子中run()方法中在i等于9时调用了interrupt()修改了该线程的中断标识位,但是线程并没有立即结束自身的运行,这是由于while中的条件决定的,我们可以通过这种方式在线程中断前做一些最后的工作。
注意:可以是线程自己修改自己的中断状态位来中断自己,即在自己的run方法中调用自己interrupt方法;也可以是一个线程的run方法中修改另一线程的状态位。
isInterrupted()
isInterrupted()也是一个实例方法,用于测试线程是否已经中断。线程的中断状态不受该方法的影响。如果该线程已经中断,则返回 true;否则返回 false。
源码:
public boolean isInterrupted() {
return isInterrupted(false);
}
底层调用的本地方法isInterrupted,传入一个boolean类型的参数,用于指定调用该方法之后是否需要清除该线程对象的中断标识位。从这里我们也可以看出来,调用isInterrupted并不会清除线程对象的中断标识位。
interrupted()
interrupted()方法是一个静态方法,同样也用于测试线程是否已经中断。但是线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
源码:
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
从它调用本地方法传入的参数,我们也可看出它会清除线程对象的标识位。
例如:
public class Test {
static int i = 0;
static class MyThread implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
while (!Thread.currentThread().isInterrupted() && i < 16) {
System.out.println(i++);
if (i == 9) {
Thread.currentThread().interrupt();
System.out.println("线程中断标识位:" + Thread.currentThread().interrupted());
System.out.println("线程中断标识位:" + Thread.currentThread().interrupted());
}
}
}
}
public static void main(String[] args) {
new Thread(new MyThread()).start();
}
}
运行结果:
上述例子中,while中的条件为:“!Thread.currentThread().isInterrupted() && i < 16”,理应在调用Thread.currentThread().interrupt()方法后线程标识位变为true,并且线程停止运行。但是在调用interrupt()方法后,两次调用的interrpted()方法返回的结果不同,并且while循环继续执行,可见interrpted()方法会改变线程的中断标识位。