跳到主要内容

线程生命周期与中断语义

Java 线程从创建到终止只会经历有限的状态。中断会向目标线程发出取消请求,并不会强制停止线程;任务是否以及何时退出,由运行中的代码和阻塞 API 共同决定。

1. start() 才会创建并发执行

Thread worker = new Thread(() -> loadData());
worker.start();
worker.join();

线程对象刚创建时是 NEWstart() 将它调度执行,调用者和新线程可以并发运行;直接调用 worker.run() 只是当前线程中的普通方法调用。

一个 Thread 只能启动一次。run 正常返回或抛出的未捕获异常处理结束后,线程进入 TERMINATED,不能重新启动。

2. 六种状态描述等待原因

Thread.State含义
NEW尚未启动
RUNNABLE正在 JVM 中执行或等待操作系统调度
BLOCKED等待进入 synchronized monitor
WAITING无期限等待另一个动作,例如 join()wait()park()
TIMED_WAITING带期限的等待,例如 sleep 或超时等待
TERMINATED执行已经结束

Java 的 RUNNABLE 不等于此刻正在占用 CPU,也可能包含某些 native I/O 状态。诊断必须把线程状态和栈、队列、CPU 一起看。

3. 中断是一个可协作的请求

while (!Thread.currentThread().isInterrupted()) {
processNextBatch();
}

interrupt() 设置目标线程的中断状态。普通计算不会因此自动终止;任务需要定期检查状态,或者调用能响应中断的阻塞方法。

isInterrupted() 只读取状态。静态方法 Thread.interrupted() 读取当前线程的状态并将其清除,通常不应被当成普通查询方法。

4. InterruptedException 需要继续传递取消信号

sleepwaitjoin 以及很多 JUC 阻塞方法在响应中断时会抛出 InterruptedException,并先清除中断状态。调用方通常有两种正确选择:

public Result load() throws InterruptedException {
return queue.take(); // 继续向上抛出
}

或者在不能继续抛出时恢复状态:

try {
return queue.take();
} catch (InterruptedException exception) {
Thread.currentThread().interrupt();
throw new TaskCancelledException(exception);
}

捕获后只记录日志并继续执行,会吞掉上层的关闭或取消请求。

5. 安全终止需要清理协议

任务退出前仍要释放锁、归还连接并关闭资源,所以不要用 Thread.stop() 破坏任意执行点的状态。推荐的关闭流程是:停止接收新任务、发出中断或设置受同步保护的停止条件、等待已有任务在期限内结束,最后处理未完成任务。

线程池应使用 shutdown() 开始有序关闭;超时后再根据业务语义决定是否调用 shutdownNow()。后者主要尝试中断正在执行的任务,并返回尚未开始的任务,不保证任务立即停止。

6. 常见问题

6.1 sleepwait 的区别是什么

sleepThread 的定时暂停,不会释放已持有的 monitor。wait 是对象 monitor 的条件等待,调用者必须持有该 monitor,进入等待时会释放它。

6.2 中断一个正在做网络 I/O 的线程一定有效吗

取决于 API。可中断通道会关闭通道并抛出 ClosedByInterruptException;其他库或 native 调用可能采用不同协议。需要查具体 API,并为外部调用配置超时。

7. 面试题

7.1 Java 中怎样正确停止一个线程

出现公司:拼多多、美团

考察重点

  • 中断是协作式请求。
  • 阻塞方法与中断状态的关系。
  • 退出前的资源清理和超时。

相关内容:第 3 节“中断是一个可协作的请求”至第 5 节“安全终止需要清理协议”。

参考回答

调用方通过 interrupt() 发出请求;任务在循环边界检查中断状态,阻塞时使用可中断 API。捕获 InterruptedException 后应继续抛出,或者在转换异常前恢复中断状态,不能无条件吞掉。

停止线程池时先 shutdown(),在期限内等待任务结束,必要时再 shutdownNow()。任务本身仍要设计幂等或补偿逻辑,并在 finally 或资源作用域内完成清理。