在 Java 并发编程中,线程的暂停、唤醒与状态切换是核心知识点,而 sleep、wait-notify、park-unpark、yield 这四种方法,常常因为都能影响线程状态而被混淆。但它们的设计初衷、底层机制、使用场景都有不小的差别,因此区分这几个方法,更有助于我们理解 Java 线程的状态转换,有利于并发编程。

Java的线程状态

想要理解 Java 线程之间的状态转换,必须要先知道 Java 线程有哪些状态。

  • NEW:尚未启动的线程状态,即线程创建

  • RUNNABLE:操作系统层面线程 READY + RUNNING 状态的集合

  • BLOCKED:等待锁时线程阻塞

  • WAITING:等待另一个线程执行特定的操作

  • TIMED_WAITING:具有指定等待时间的 WAITING 状态

  • TERMINATED:线程完成执行

这是线程之间状态转换图,至于如何转换呢,正需要我们步入主题,正式讲解sleep、wait-notify、park-unpark、yield。

基本概念

  • Thread.sleep(long millis):属于Thread类的静态方法,核心作用是让当前线程暂停执行指定时间,期间不释放已持有的锁资源,设计初衷是“简单的时间等待”。

  • Object.wait()/notify()/notifyAll():属于Object类的方法,必须在同步块(synchronized)中使用,核心作用是实现线程间的协作通信,wait会释放锁,notify/notifyAll会唤醒等待线程,设计初衷是“基于锁的线程同步”。

  • LockSupport.park()/unpark(Thread thread):属于JUC包下的工具类方法,可精准唤醒指定线程,设计初衷是“更灵活的线程阻塞控制”。

  • Thread.yield():属于Thread类的静态方法,核心作用是让当前线程主动放弃CPU执行权,重新进入就绪队列竞争CPU,设计初衷是“调节线程优先级,优化CPU调度”。

逐一拆解

Thread.sleep()

sleep 是 Thread 类里的方法,这说明可以在任意地方调用sleep。调用 sleep 后,其对应的线程将要暂停运行指定的时间,在此期间释放 CPU 的资源,但不涉及锁方面。

线程调用 sleep 后,状态会立即从 RUNNABLE 变为 TIMED_WAITING,当经过指定的超时时间,将自动转换为 RUNNABLE 状态。

Object.wait-notify

wait、notify 是 Object 类里的方法,这说明必须在 synchronized 同步块或方法中使用。调用 wait 后,线程会暂停运行,同时释放所持有的对象锁资源并释放 CPU。

线程调用 wait 后,状态会立即从 RUNNABLE 变为 WAITING(无超时)或 TIMED_WAITING(带超时),需通过 notify 唤醒或超时后,转换为 RUNNABLE 状态参与锁竞争。

LockSupport.park-unpark

park、unpark 是 LockSupport 类里的方法。调用 park 后,线程会暂停运行并释放 CPU 资源。unpark 则为指定线程发放许可,唤醒被阻塞的线程。

线程调用 park 后,状态会立即从 RUNNABLE 变为 WAITING(无超时)或 TIMED_WAITING(带超时),被 unpark 唤醒、中断或超时后,转换为 RUNNABLE 状态。

Thread.yield()

yield 是 Thread 类里的方法,这说明可以在任意地方调用 yield。调用 yield 后,线程会主动放弃当前 CPU 时间片,释放 CPU 资源,但不涉及锁方面,也不会暂停运行。

线程调用 yield 后,状态始终保持 RUNNABLE,仅从 RUNNING 转为 READY,重新参与 CPU 调度竞争,调度器可能忽略该暗示,让其再次获取 CPU。

一图理解状态转换

经过上文的讲解,线程状态之间是如何切换的应该不难理解了。我再把一开始放出的图填空一下,便可以更清晰地认识线程状态是如何变化的。

根据上述分析,我们可以根据场景精准选用方法:

  1. 若仅需简单时间延迟,不涉及线程协作 → 用sleep。

2. 若需基于 synchronized 锁实现线程间协作通信 → 用wait-notify。

3. 若需精准唤醒指定线程,在JUC组件中控制线程 → 用park-unpark。

4. 若需低优先级线程主动让渡CPU,优化调度效率 → 用yield(谨慎使用,效果不确定)。

掌握这四种方法的差异,核心是理解“锁资源处理”和“唤醒机制”两大核心维度。在实际开发中,优先使用JUC提供的工具类(如Lock、Condition、LockSupport),它们比原生的wait-notify更灵活、更安全,能有效避免死锁、虚假唤醒等问题。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐