为什么不推荐使用 Thread.stop()
方法终止线程及安全隐患
- 立即释放锁:
Thread.stop()
方法会立即终止线程,并释放该线程所持有的所有锁。这可能导致对象处于不一致的状态。例如,在一个银行转账操作中,线程可能已经完成了从一个账户扣款,但还未完成向另一个账户存款时被 stop
,由于锁被释放,其他线程可能访问到这个不一致的账户状态,引发数据错误。
- 不可控性:
stop
方法是不安全且不可控的,它不会给线程任何机会来清理资源,如关闭文件句柄、数据库连接等。这可能导致资源泄漏,影响系统的稳定性和性能。
安全终止线程的策略及优缺点
1. 使用标志位
- 实现方式:在线程类中定义一个
volatile
类型的布尔变量作为标志位。线程在运行过程中,周期性地检查这个标志位。当标志位被设置为 false
时,线程结束运行。
public class ThreadTerminationByFlag {
private static volatile boolean stopRequested = false;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (!stopRequested) {
// 线程执行的任务
System.out.println("Thread is running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread stopped.");
});
thread.start();
// 主线程睡眠3秒后设置标志位
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
stopRequested = true;
}
}
- 优点:实现简单,对代码侵入性小。线程可以在合适的时机响应终止请求,有机会清理资源,保证数据一致性。
- 缺点:如果线程长时间阻塞在某个操作上(如
Thread.sleep
,Object.wait
等),可能不能及时响应标志位变化。需要手动处理阻塞情况,如在 sleep
时捕获 InterruptedException
异常来提前结束阻塞。
2. 使用 interrupt()
方法
- 实现方式:通过调用线程的
interrupt()
方法设置线程的中断标志位。线程通过检查 isInterrupted()
方法或者捕获 InterruptedException
异常来处理中断请求。
public class ThreadTerminationByInterrupt {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 线程执行的任务
System.out.println("Thread is running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 捕获到中断异常,清理资源并结束线程
Thread.currentThread().interrupt(); // 重新设置中断标志位,以便上层调用者知晓中断发生
System.out.println("Thread interrupted, cleaning up and stopping.");
break;
}
}
System.out.println("Thread stopped.");
});
thread.start();
// 主线程睡眠3秒后中断线程
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
- 优点:具有较好的灵活性和通用性。可以中断阻塞在
sleep
、wait
、join
等方法上的线程,并且线程可以在捕获到中断异常时进行资源清理等操作。
- 缺点:需要正确处理
InterruptedException
异常,并且在某些情况下,如线程中使用了第三方库且该库没有正确处理中断,可能导致线程无法正常响应中断。此外,处理不当可能丢失中断信号,导致线程无法按预期终止。