如何停止一个运行的线程
正确的答案是:使用协作式的中断机制,而不是强制停止。
停止线程的最佳实践:
- 使用中断机制:
thread.interrupt()+ 检查 ``thread.isInterrupted()` - 使用标志位:
volatile boolean running,保证可见性 - 处理阻塞操作:对 sleep、wait、I/O 等要特殊处理
- 资源清理:在 finally 块中释放资源
- 使用线程池:优先使用
ExecutorService的shutdown()和shutdownNow() - 使用
return提前结束线程
Thread.stop() - ❌ 绝对不要使用!
为什么不能使用 stop()?
- 会立即释放该线程持有的所有锁,可能导致数据处于不一致状态
- 无法执行清理工作,可能造成资源泄漏
- 行为不可预测,是线程不安全的
而且 stop方法已经是被废弃的方法。
# 检查中断状态(推荐)
即 interrupt() 和 isInterrupted() 配合使用
public class CorrectWay1 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
// 定期检查中断状态
while (!Thread.currentThread().isInterrupted()) {
System.out.println("线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 当sleep时被中断,会清除中断状态并抛出异常
System.out.println("收到中断信号,准备退出...");
// 重新设置中断状态,让循环条件能检测到
Thread.currentThread().interrupt();
}
}
System.out.println("线程安全退出");
});
thread.start();
Thread.sleep(3000);
// ✅ 正确方式:发出中断信号
thread.interrupt();
}
}
# 方式二:通过 volatile 标志位
public class CorrectWay2 {
// 使用 volatile 保证可见性
private static volatile boolean running = true;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (running) {
System.out.println("线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("睡眠被中断,但继续运行");
}
}
System.out.println("线程安全退出");
});
thread.start();
Thread.sleep(3000);
// ✅ 通过标志位停止线程
running = false;
thread.interrupt(); // 如果线程在sleep,需要中断来立即唤醒
}
}
# 三. ExecutorService
public class ExecutorShutdown {
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交任务
for (int i = 0; i < 5; i++) {
final int taskId = i;
executor.submit(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("任务 " + taskId + " 执行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("任务 " + taskId + " 被中断");
Thread.currentThread().interrupt();
}
}
System.out.println("任务 " + taskId + " 退出");
return taskId;
});
}
Thread.sleep(3000);
// ✅ 优雅关闭线程池
System.out.println("开始关闭线程池...");
// 1. 停止接受新任务,执行已提交的任务
executor.shutdown();
// 2. 等待一段时间让任务完成
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
System.out.println("还有任务未完成,尝试强制关闭...");
// 3. 强制取消所有运行中的任务
List<Runnable> notExecuted = executor.shutdownNow();
System.out.println("被取消的任务数量: " + notExecuted.size());
}
System.out.println("线程池已关闭");
}
}
# 四、实践
结合业务自身逻辑进行封装,触发停止线程操作,还有线程停止后要做自身逻辑。
public class GracefulShutdown {
private volatile boolean running = true;
private final Thread workerThread;
public GracefulShutdown() {
this.workerThread = new Thread(this::doWork);
}
public void start() {
workerThread.start();
}
public void stop() {
running = false;
workerThread.interrupt(); // 中断可能存在的阻塞操作
}
private void doWork() {
try {
while (running && !Thread.currentThread().isInterrupted()) {
System.out.println("执行工作任务...");
// 模拟工作 - 包含可能阻塞的操作
performTask();
// 定期检查停止条件
if (!running) {
System.out.println("收到停止信号,准备退出...");
break;
}
}
} finally {
// 清理资源
cleanup();
}
System.out.println("工作线程已停止");
}
private void performTask() {
try {
// 可能阻塞的操作
Thread.sleep(2000);
// 可能抛出异常的操作
if (Math.random() < 0.1) {
throw new RuntimeException("模拟业务异常");
}
} catch (InterruptedException e) {
System.out.println("工作被中断");
Thread.currentThread().interrupt();
} catch (Exception e) {
System.out.println("处理业务异常: " + e.getMessage());
// 根据业务决定是否继续执行
}
}
private void cleanup() {
System.out.println("执行清理工作...");
// 关闭文件、数据库连接、释放资源等
}
public static void main(String[] args) throws InterruptedException {
GracefulShutdown service = new GracefulShutdown();
service.start();
// 运行10秒后停止
Thread.sleep(10000);
service.stop();
// 等待线程完全停止
service.workerThread.join(5000);
if (service.workerThread.isAlive()) {
System.out.println("警告:线程未在指定时间内停止");
}
}
}
上次更新: 2025-12-04 03:34:09