【线程有哪些状态?这些状态如何相互转换?阻塞和等待的状态有什么区别?】

发布于:2025-04-11 ⋅ 阅读:(26) ⋅ 点赞:(0)

线程状态及其转换与区别

线程的生命周期包含多个状态,不同状态之间的转换由线程调度和同步机制决定。以下是线程状态的详细说明、转换关系及阻塞与等待的区别:


一、线程的六种基本状态(以Java为例)

状态 描述
NEW(新建) 线程被创建但未启动(start() 尚未调用)。
RUNNABLE(可运行) 线程已启动,可能正在运行或等待CPU时间片(包含操作系统的就绪和运行状态)。
BLOCKED(阻塞) 线程因等待获取锁而无法进入同步块/方法(如其他线程持有锁)。
WAITING(等待) 线程主动进入无限期等待,需其他线程显式唤醒(如调用 wait()join())。
TIMED_WAITING(计时等待) 线程在指定时间内等待(如 sleep(ms)wait(timeout))。
TERMINATED(终止) 线程执行完毕或异常退出。

二、状态转换关系与触发条件

  1. NEW → RUNNABLE
    触发条件:调用 start() 方法启动线程。

  2. RUNNABLE ↔ RUNNING(操作系统层面)
    运行 → 就绪:时间片用完或被更高优先级线程抢占(由操作系统调度决定)。
    就绪 → 运行:被操作系统调度选中,分配CPU时间片。

  3. RUNNABLE → BLOCKED
    触发条件:尝试进入同步块/方法时,锁已被其他线程持有。
    示例:线程A持有锁,线程B尝试进入同步块时被阻塞。

  4. RUNNABLE → WAITING
    触发条件:调用无超时的 wait()join()LockSupport.park()
    示例:线程调用 object.wait() 主动释放锁并进入等待队列。

  5. RUNNABLE → TIMED_WAITING
    触发条件:调用带超时的 sleep(ms)wait(timeout)join(timeout)
    示例:线程调用 Thread.sleep(1000) 休眠1秒。

  6. BLOCKED → RUNNABLE
    触发条件:锁被释放(如持有锁的线程退出同步块)。
    示例:线程A释放锁后,线程B成功获取锁并恢复执行。

  7. WAITING/TIMED_WAITING → RUNNABLE
    触发条件
    WAITING:其他线程调用 notify()/notifyAll() 或发生中断。
    TIMED_WAITING:超时时间到或被唤醒。
    示例:线程调用 object.wait(5000),5秒后自动恢复。

  8. RUNNABLE → TERMINATED
    触发条件:线程正常执行完毕或抛出未捕获异常。


三、阻塞(BLOCKED)与等待(WAITING)的区别

维度 BLOCKED(阻塞) WAITING(等待)
触发原因 被动等待锁(竞争同步资源失败)。 主动释放锁并等待条件(如调用 wait())。
锁状态 未持有锁,等待获取锁。 已释放锁,等待其他线程唤醒。
唤醒机制 锁被释放时自动竞争。 需其他线程显式唤醒(notify()/notifyAll())或中断。
典型场景 多线程竞争同一同步块。 生产者-消费者模型中的条件等待。
代码示例 synchronized(obj) { ... } 竞争失败时。 synchronized(obj) { obj.wait(); }

四、状态转换流程图

          start()
NEW ────────────────> RUNNABLE
                        │
                        │ 获取CPU时间片
                        ↓
                     RUNNING (操作系统层面)
                        │
                        │ 时间片用完/被抢占
                        ↓
                      RUNNABLE
                        │
                        ├─ 尝试获取锁失败 ────> BLOCKED
                        │
                        ├─ 调用 wait()/join() ──> WAITING
                        │
                        ├─ 调用 sleep(ms) ────> TIMED_WAITING
                        │
                        └─ 执行完成/异常 ─────> TERMINATED

五、关键总结

  1. BLOCKED 与 WAITING 的核心区别
    BLOCKED 是线程被动等待锁,未持有锁;WAITING 是线程主动释放锁后等待条件。
    BLOCKED 由锁竞争触发,WAITING 由显式调用等待方法触发。

  2. 状态转换的核心逻辑
    • 线程状态的切换依赖于锁机制、同步方法和操作系统调度。
    TIMED_WAITING 是带有超时的等待,可避免无限期阻塞。

  3. 实际应用建议
    • 避免过度使用 BLOCKED(如减少锁竞争),优先考虑无锁数据结构。
    • 使用 WAITINGTIMED_WAITING 实现线程协作时,需注意死锁和资源泄漏问题。

通过理解线程状态及其转换,开发者能更高效地设计并发程序,并快速定位死锁、资源竞争等问题。