Java 的线程中断是一种协作请求,不是强制终止。调用者发出请求,执行线程按自身控制流响应并清理资源;如果线程从不检查中断,或阻塞操作不响应它,请求就不一定及时结束工作。

三个名字相近的方法

方法含义
target.interrupt()向目标线程发出中断请求
target.isInterrupted()读取目标线程的中断状态,不清除
Thread.interrupted()检查并清除当前线程的中断状态

Thread.interrupted 是静态方法。通过某个线程变量调用它,也不会变成检测那个目标线程。循环里如果只想检测而不消费标记,通常使用当前线程的 isInterrupted。Java 8 Thread

不要使用已废弃的 Thread.stop 强制终止工作。它可能在不变量尚未恢复时释放监视器,造成其他线程观察到不一致状态。

让运行代码真正走到退出路径

以下 Java 8 示例用 CountDownLatch 协调“线程已经启动”,不依赖主线程猜测等待几秒:

import java.util.concurrent.CountDownLatch;

public class InterruptExitDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch started = new CountDownLatch(1);
        Thread worker = new Thread(() -> {
            try {
                started.countDown();
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Thread.sleep(100); // 用等待代表一个有界工作步骤
                    } catch (InterruptedException error) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            } finally {
                System.out.println("执行资源清理");
            }
        });

        worker.start();
        started.await();
        worker.interrupt();
        worker.join();
    }
}

sleep 抛出 InterruptedException 时会清除中断状态。这里恢复标记并离开当前任务,而不是打印堆栈后继续无限循环。无论请求发生在条件检查还是等待阶段,finally 都是清理路径。

示例中的 join 等待线程退出;真实应用应根据关闭时限决定是否使用有界等待,并处理等待者自身被中断的情况。

break 不等于离开 run

break 只跳出当前循环,循环之后的代码仍会继续执行。return 离开当前方法;若它就在 run 内,run 将结束。也可以让一个声明 InterruptedException 的业务方法向上传播,再由任务边界决定退出。

不需要为了停止而刻意制造异常;关键是取消信号有没有到达应该停止的边界。无法向上传播、但上层仍需识别中断时,恢复标记通常比吞掉它更合适。

中断不替代所有取消机制

wait、sleep、join 有相应中断语义,但不能推广为所有网络、文件或第三方调用都会立刻终止。业务还可能需要关闭资源、超时、取消令牌和远端补偿。

即使停止请求与正常完成竞争,也应只进行一次必要清理;取消本地线程不代表已发生的远端操作自动回滚。