Java 线程与 Runnable

Thread 与 Runnable 如何启动并发任务:线程生命周期入口、start/run 区别与基本退出意识。

#type / concept #status / growing #tech / dev #resource / java

[!info] 关联笔记

Java 线程与 Runnable

这个概念为什么出现

服务要同时处理多个请求、后台刷新缓存、异步发消息。Java 的经典并发起点是 线程(Thread) 与任务抽象 Runnable/Callable。先分清“任务”和“执行线程”,后面的线程池才有意义。

[!abstract] 一句话理解 Runnable 描述要做的事;Thread.start() 才会真正启动新线程并发执行,直接调用 run() 只是普通方法调用。

最小可运行示例

场景:下单后异步写审计日志,不阻塞主请求线程

public class AuditAsync {
    static void handleOrder(String orderId) throws InterruptedException {
        // 主线程:快速返回业务结果
        System.out.println("accepted " + orderId + " on " + Thread.currentThread().getName());

        Thread audit = new Thread(() -> {
            // 审计任务:模拟写日志
            System.out.println("audit " + orderId + " on " + Thread.currentThread().getName());
        }, "audit-worker");
        audit.start(); // 启动并发,而不是 audit.run()
        audit.join();  // 演示中等待结束;真实服务常用线程池且不在请求线程 join
    }

    public static void main(String[] args) throws Exception {
        handleOrder("ORD-1");
    }
}

建议运行:

javac AuditAsync.java && java AuditAsync

期望输出(线程名可能略有差异,但 audit 行应出现):

accepted ORD-1 on main
audit ORD-1 on audit-worker

结合场景再看三个关注点

  1. start 才创建新并发执行
  2. 任务里未捕获的异常默认不会回到 main。
  3. 生产应优先线程池,避免无限制 new Thread

核心概念与准确模型

1. 线程 vs 任务

  • 任务:Runnable/Callable
  • 执行者:ThreadExecutor

2. 生命周期直觉

NEW → RUNNABLE → 阻塞/等待 → TERMINATED(简化)

3. 中断

  • interrupt 协作式取消
  • 阻塞调用抛 InterruptedException 时应恢复中断状态或退出

4. 守护线程

  • setDaemon(true) 不阻止 JVM 退出——勿用于必须完成的事务。

边界情况与反直觉行为

  1. 共享可变状态无同步 → 数据竞争(见后文)。
  2. join 死等导致请求线程卡死。
  3. 线程名对排障极重要。

常见误区

[!warning] 常见误区:用 Thread.sleep 当同步协议 sleep 不能保证可见性/事件顺序;用锁、并发工具或 join/future。

工程实践

  1. 业务代码面向 Executor。
  2. 命名线程。
  3. 设置未捕获异常处理器。
  4. 明确取消与超时策略。

本节总结

  • Runnable 是任务,Thread 是载体
  • start ≠ run
  • 为线程池与同步打基础

自测题

  1. 为什么不要在生产循环里无限 new Thread?
  2. 捕获 InterruptedException 后应怎样处理中断状态?
参考答案
  1. 无法统一限流、复用与关闭,易耗尽资源。
  2. 重新设置中断标志或结束任务,避免吞掉取消信号。

延伸阅读与资料来源

资料类型支撑内容
Thread (API)API线程
Concurrency (Oracle Tutorial)教程并发入门
创建于 2026/7/15 更新于 2026/7/15