在 Java 中,关闭线程或线程池需要遵循特定的规范,直接强制终止线程可能导致资源泄露或数据不一致。
以下是关闭 线程 和 线程池 的常用方法:
单个线程的关闭需通过 “协作式” 方式,而非强制终止(stop() 等方法已废弃,会导致线程立即终止,释放所有监视器锁,造成数据安全问题)。
interrupt() 配合中断标记通过 interrupt() 方法设置线程的中断标记,线程内部通过 isInterrupted() 检测标记并主动退出。
public class InterruptThreadExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
// 循环检测中断标记
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("线程运行中...");
Thread.sleep(1000); // 阻塞方法会响应中断
} catch (InterruptedException e) {
// 捕获中断异常后,中断标记会被清除,需手动重新设置
System.out.println("线程被中断,准备退出");
Thread.currentThread().interrupt(); // 重新设置中断标记
}
}
System.out.println("线程已退出");
});
thread.start();
Thread.sleep(3000); // 运行3秒后关闭线程
thread.interrupt(); // 发送中断信号
}
}
原理:
interrupt() 不会直接终止线程,仅设置中断标记。isInterrupted())或响应阻塞方法(sleep()、wait() 等)抛出的 InterruptedException,并在合适时机退出。通过自定义布尔变量作为线程运行的条件,外部修改该变量触发线程退出。
public class CustomFlagThreadExample {
private static volatile boolean isRunning = true; // volatile 保证可见性
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (isRunning) { // 检测自定义标记
System.out.println("线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println("线程已退出");
});
thread.start();
Thread.sleep(3000);
isRunning = false; // 修改标记,触发线程退出
}
}
注意:标记需用 volatile 修饰,确保多线程间的可见性。
线程池提供了专门的方法关闭线程,确保任务有序结束并释放资源。
shutdown():温和关闭SHUTDOWN。ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交任务...
executor.shutdown(); // 温和关闭
shutdownNow():强制关闭interrupt() 方法中断任务,若任务不响应中断,可能无法立即终止。STOP。ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交任务...
List<Runnable> unexecutedTasks = executor.shutdownNow(); // 强制关闭,返回未执行的任务
System.out.println("未执行的任务数:" + unexecutedTasks.size());
awaitTermination() 等待关闭完成用于等待线程池彻底关闭(所有任务执行完毕),避免主线程提前退出。
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交任务...
executor.shutdown();
try {
// 等待60秒,若线程池在60秒内关闭则返回true,否则返回false
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
// 若超时未关闭,可尝试强制关闭
executor.shutdownNow();
}
} catch (InterruptedException e) {
// 等待过程中被中断,需再次强制关闭
executor.shutdownNow();
}
Thread.stop()、Thread.suspend()、Thread.resume() 已废弃,会导致线程状态不一致或死锁。interrupt() 终止任务,若任务中包含 while(true) 等不响应中断的逻辑,可能导致线程无法关闭。shutdown() 或 shutdownNow() 后,再提交任务会抛出 RejectedExecutionException。interrupt() 或自定义标记实现 “协作式” 退出,禁止使用强制终止方法。shutdown() 温和关闭,配合 awaitTermination() 确保关闭完成;必要时用 shutdownNow() 强制关闭,但需处理未执行的任务。合理关闭线程 / 线程池是保证程序稳定性和资源安全的重要环节。