必须调用start()而非run()启动线程;run()仅为普通方法调用,不创建新线程;继承Thread或使用Runnable+Thread均可,但推荐后者以解耦任务与执行;lambda需捕获final或事实final变量;构造函数中不可调用start()以防引用逸出;启动后执行时机不确定,需用join()或同步工具协调。

直接用 Thread 构造函数启动线程,但别忘了调用 start()
最基础的方式是继承 Thread 类并重写 run() 方法,然后实例化后调用 start()。关键点在于:绝不能直接调用 run() —— 那只是普通方法调用,不会开启新线程,所有代码仍在当前线程执行。
常见错误现象:thread.run() 看似“运行了”,但调试时发现 Thread.currentThread().getName() 始终是 main;CPU 时间片没被抢占,多线程效果完全消失。
- 必须用
new MyThread().start(),不是.run() - 重写的
run()方法里不要抛出受检异常(Exception),因为Thread的run()声明不抛异常;如需处理 I/O 异常,得在内部try-catch - 构造函数中传入的
Runnable对象,和继承Thread是两条路,别混用(比如 new Thread(() -> {}).run())
用 Runnable + Thread 组合更灵活,推荐优先使用
Runnable 是函数式接口,只定义一个 run() 方法,天然适合 lambda 表达式。它把“要做什么”和“由谁执行”解耦,避免单继承限制,也更容易复用任务逻辑。
使用场景:多个线程执行相同任务逻辑(比如批量处理日志)、任务需被不同执行器调度(后续可无缝切换到 ExecutorService)。
立即学习“Java免费学习笔记(深入)”;
-
new Thread(() -> System.out.println("Hello")).start();是最简写法 - 若需访问外部变量,变量必须是
final或“事实 final”(Java 8+) - 注意:lambda 内部捕获的局部变量,不能在 lambda 外部修改,否则编译报错
local variables referenced from a lambda expression must be final or effectively final
别在构造函数里启动线程,否则可能引发状态泄漏
如果自定义 Thread 子类,在构造函数中就调用 this.start(),会导致对象尚未初始化完成就被其他线程访问 —— 特别是当子类有字段需要初始化、或父类构造器还没走完时,极易出现 NullPointerException 或读到默认值(如 0、null)。
典型错误模式:
class BadWorker extends Thread {
private final String name;
public BadWorker(String name) {
this.name = name;
start(); // ❌ 危险!此时 this 引用已逸出
}
public void run() {
System.out.println("Name: " + name); // 可能打印 null
}
}
- 启动线程的动作必须放在构造完成之后,比如工厂方法返回后再调用
start() - 如果必须封装启动逻辑,改用静态工厂方法:
public static BadWorker createAndStart(String name) { BadWorker w = new BadWorker(name); w.start(); return w; } - 更安全的做法:彻底放弃继承
Thread,改用Runnable+ 显式Thread实例
启动后无法保证立即执行,也不该依赖执行顺序
调用 start() 只是向 JVM 提交调度请求,线程进入 RUNNABLE 状态,但何时真正获得 CPU 时间片由操作系统调度器决定。即使在单核机器上,也可能因上下文切换延迟几十毫秒。
常见误判:在主线程 start() 后立刻读共享变量,认为“它肯定已更新”,结果读到旧值 —— 这不仅是执行时机问题,更是可见性问题(缺少 volatile 或同步)。
- 不要用
Thread.sleep(10)来“等线程跑起来”,这是不可靠的竞态修复 - 如需等待线程完成,用
thread.join();如需协调状态,用CountDownLatch、CyclicBarrier等显式同步工具 - 任何跨线程读写共享变量,必须通过同步机制(
synchronized、volatile、java.util.concurrent类型)保证可见性和原子性
start() 和 run() 的语义鸿沟,以及 lambda 捕获变量的生命周期约束。










