HelloCoder HelloCoder
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
随笔
关于作者
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
随笔
关于作者
  • 《LearnJavaToFindAJob》

    • 导读

    • 【初级】6~12k档

    • 【中级】12k-26k档

    • 【高级】26k+档

    • 大厂面试题

      • IBM面试题-不借助变量交换两个数
      • 奇怪的面试题
      • 如何停止一个运行的线程
      • 快手

      • 美团

      • 腾讯

      • 阿里

    • 求职建议

    • 面经

  • LearnJavaToFindAJob
  • 大厂面试题
#线程
码农阿雨
2025-12-04
目录

如何停止一个运行的线程

正确的答案是:使用协作式的中断机制,而不是强制停止。

停止线程的最佳实践:

  1. 使用中断机制:thread.interrupt() + 检查 ``thread.isInterrupted()`
  2. 使用标志位:volatile boolean running,保证可见性
  3. 处理阻塞操作:对 sleep、wait、I/O 等要特殊处理
  4. 资源清理:在 finally 块中释放资源
  5. 使用线程池:优先使用 ExecutorService 的 shutdown() 和 shutdownNow()
  6. 使用 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("警告:线程未在指定时间内停止");
        }
    }
}
阅读全文
×

(为防止恶意爬虫)
扫码或搜索:HelloCoder
发送:290992
即可永久解锁本站全部文章

解锁
#线程
上次更新: 2025-12-04 03:34:09
最近更新
01
MySQL支持的锁有哪些
12-04
02
Synchronized相关
12-04
03
synchronized锁升级
12-04
更多文章>
Theme by Vdoing | Copyright © 2020-2025 码农阿雨
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式