线程自然终止
要么是run执行完成了,要么是抛出了一个未处理的异常导致线程提前结束。
暴力终止
暂停、恢复和停止操作对应在线程 Thread 的 API 就是 suspend()、resume() 和 stop()。但是这些 API 是过期的,也就是不建议使用的。不建议使用的原因主 要有:以 suspend()方法为例,在调用后,线程不会释放已经占有的资源(比如 锁),而是占有着资源进入睡眠状态,这样容易引发死锁问题。同样,stop()方法 在终结一个线程时不会保证线程的资源正常释放,通常是没有给予线程完成资源
释放工作的机会,因此会导致程序可能工作在不确定状态下。正因为 suspend()、 resume()和 stop()方法带来的副作用,这些方法才被标注为不建议使用的过期方 法。
中断
JDK Thread.java的方法:
// 静态方法,测试当前线程是否被中断,线程的中断状态由该方法清除
public static boolean interrupted()
// 测试当前线程是否被中断,不清楚状态标志
public boolean isInterrupted()
// 中断线程
public void interrupt()
安全的中止则是其他线程通过调用某个线程 A 的 interrupt()方法对其进行中断操作, 中断好比其他线程对该线程打了个招呼,“A,你要中断了”,不代表线程 A 会立即停止自己的工作,同样的 A 线程完全可以不理会这种中断请求。因 为 java 里的线程是协作式的,不是抢占式的。线程通过检查自身的中断标志位是否被置为 true 来进行响应,线程通过方法 isInterrupted()来进行判断是否被中断,也可以调用静态方法 Thread.interrupted()来进行判断当前线程是否被中断,不过 Thread.interrupted() 会同时将中断标识位改写为 false。
如果一个线程处于了阻塞状态(如线程调用了 thread.sleep、thread.join、 thread.wait 等),则在线程在检查中断标示时如果发现中断标示为 true,则会在这些阻塞方法调用处抛出 InterruptedException 异常,并且在抛出异常后会立即将线程的中断标示位清除,即重新设置为 false。
下面代码在线程run方法中调用sleep,在主线程调用thread.interrupt()来设置中断状态。从运行结果看出线程在阻塞时检测到中断状态为true,抛出InterruptedException异常,isInterrupted为false。
public class StopThread {
public static void main(String[] args) {
try {
Mythread thread = new Mythread();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch (Exception e) {
System.out.println("Main catch");
e.printStackTrace();
}
System.out.println("main end");
}
}
class Mythread extends Thread{
@Override
public void run(){
try {
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e){
System.out.println("在沉睡中被停止!进入catch "+this.isInterrupted());
e.printStackTrace();
}
}
}
不建议自定义一个取消标志位来中止线程的运行。因为run方法里有阻塞调用时会无法很快检测到取消标志,线程必须从阻塞调用返回后,才会检查这个取消标志。这种情况下,使用中断会更好,因为,
- 一般的阻塞方法,如 sleep 等本身就支持中断的检查(见上面示例),
- 检查中断位的状态和检查取消标志位没什么区别,用中断位的状态还可以避免声明取消标志位,减少资源的消耗。
注意:处于死锁状态的线程无法被中断
参考:高洪岩《Java多线程编程核心技术》