启动线程必须用start()而非run(),因为start()真正实现并发执行,而run()只是串行调用;前者由jvm创建新线程、交由os调度并行运行,后者仍在主线程中顺序执行,无任何并发收益。

启动线程必须用 start(),直接调用 run() 不是多线程,性能差异本质不在“快慢”,而在“是否并发”——前者让任务并行执行,后者只是串行调用,根本没启用线程机制。
start() 启动:真正并发,CPU 时间片被共享
调用 start() 会让 JVM 创建新线程、分配独立栈空间,并将线程置为就绪(RUNNABLE)状态。它不立即执行 run(),而是交由操作系统调度——多个线程可同时争抢 CPU 时间片。比如两个耗时循环任务,用 start() 后可能总耗时接近单个任务时间(如 12ms → 约 13ms),因为它们大部分时间在并行跑。
- 每个线程拥有自己的调用栈和局部变量,互不干扰
- 主线程调用 start() 后立刻继续往下执行,无需等待子线程完成
- 实际执行顺序由调度器决定,无法保证先后
run() 直接调用:仍是单线程,纯顺序执行
这等同于普通方法调用。代码仍在主线程中运行,没有新栈、没有调度、没有并发。两个 1000 次循环的任务调用 run(),会一个接一个执行,总耗时≈两者相加(如 12ms + 12ms = 24ms),且主线程全程阻塞直到最后一个 run() 返回。
- 无额外线程开销,但也没获得任何并发收益
- 适合调试逻辑或临时复用线程类的业务代码,不能替代多线程
- 多次调用 run() 完全合法;但重复调用 start() 会抛 IllegalStateException
性能对比的关键不是毫秒数,而是执行模型
测试中看到 “start 耗时 1ms,run 耗时 12ms”,这个数字本身有误导性——1ms 是主线程发起 start() 的开销(极快),不代表整个线程执行完只用了 1ms;12ms 是主线程同步执行全部 run() 逻辑的总耗时。真正有意义的对比是:同样两个任务,start() 下整体完成更快(因并行),run() 下必然更慢(因串行)。
- 并发提升取决于任务类型:CPU 密集型受益于多核,IO 密集型受益于等待重叠
- 线程创建本身有开销,所以不是“越多越快”,需结合任务粒度权衡
- run() 看似轻量,实则是放弃了并发能力,不是优化,是退化
别混淆“启动快”和“执行快”
start() 方法本身返回极快(纳秒级),因为它只做注册和状态切换;真正的执行延迟取决于系统负载和调度时机。而 run() 调用虽“启动零开销”,却把所有工作压在主线程上,容易导致响应卡顿、吞吐下降。多线程的价值从来不是让单个方法调用变快,而是让整体系统在单位时间内完成更多工作。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











