姚同学 录屏 音乐 摸鱼 压图
线程启动

为何必须调用start()而非run()

在Java中,线程的启动必须调用Thread实例的start()方法,而非直接调用run()方法。原因如下:

run()方法只是用户编写的普通业务逻辑,不具备操作系统级别的线程调度能力;直接调用它相当于在当前线程内做一次顺序方法调用,不会创建新的调用栈。

start()方法由JVM实现,会完成与操作系统的交互:分配native线程、初始化线程私有内存、将线程状态从NEW切换为RUNNABLE,并最终回调run()方法。

若直接执行run(),程序中依旧只有一条执行路径(通常是main线程),既不能并发,也无法利用多核CPU资源,从而失去创建线程的意义。

重复调用start()的后果

Java规范明确规定:一个Thread对象的start()只能被成功调用一次。第二次及以后的调用将抛出java.lang.IllegalThreadStateException(运行时异常)。

该限制基于以下考虑:

线程生命周期不可逆。一旦线程到达TERMINATED状态,其内部状态已被回收,无法再次启动。

若允许多次启动,将破坏线程安全模型:旧栈帧、监视器锁、中断状态等资源均处于不确定状态,极易产生竞态条件或内存可见性问题。

Java线程的六种生命周期状态

JDK5以后,Thread.State枚举明确定义了6种状态:

NEW:已创建Thread实例,尚未调用start()。

RUNNABLE:线程正在JVM中执行,或已就绪等待操作系统分配CPU时间片(Java把操作系统层面的running+ready统一为RUNNABLE)。

BLOCKED:线程等待获取监视器锁(synchronized)。

WAITING:线程无条件等待,直至其他线程显式唤醒(Object.wait、Thread.join、LockSupport.park等)。

TIMED_WAITING:带超时限制的等待(Thread.sleep、Object.wait(timeout)、LockSupport.parkNanos等)。

TERMINATED:run()方法正常结束或异常退出,线程生命周期结束。

状态转换是单向不可逆的。一旦进入TERMINATED,任何试图回到RUNNABLE的操作(包括再次调用start())都会被JVM拒绝并抛出IllegalThreadStateException。

最佳实践

始终通过newThread(...).start()启动新线程;如需重复执行任务,请使用线程池(ExecutorService)或创建新的Thread实例。

在并发场景下,优先使用java.util.concurrent包提供的工具(Executor、Future、ThreadPoolExecutor等),避免手动管理裸线程。

若需保证线程安全,请结合同步机制(synchronized、java.util.concurrent.locks)与可见性语义(volatile、final、Atomic*)进行设计。