基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

Thread.sleep()、Object.wait()、Thread.yield() 和 Thread.join() 的区别是什么?

知识点图片

这四个方法都是 Java 中用于控制线程状态和调度的核心方法,但它们在所属类、是否释放锁、使用场景和底层机制上有很大的区别。

以下是它们的详细对比和解析:


1. Thread.sleep(long millis)

  • 所属类java.lang.Thread(静态方法)
  • 作用:让当前正在执行的线程暂停执行指定的时间,进入阻塞状态(TIMED_WAITING)。时间到了之后,线程会自动苏醒并进入就绪状态(RUNNABLE),等待 CPU 再次调度。
  • 关于锁绝对不会释放任何锁。如果线程在同步块(synchronized)中调用了 sleep(),它会“抱着锁睡觉”,其他等待该锁的线程依然无法进入同步块。
  • 使用场景:通常用于模拟耗时操作、定时任务、或者让出 CPU 给其他线程执行(但保留锁的使用权)。

2. Object.wait()

  • 所属类java.lang.Object(实例方法)
  • 作用:让当前线程进入等待状态(WAITINGTIMED_WAITING),直到其他线程调用同一个对象上的 notify()notifyAll() 方法将其唤醒。
  • 关于锁会释放当前对象的监视器锁(Monitor Lock)。正因为要释放锁,所以 wait() 必须且只能在 synchronized 同步代码块或同步方法中使用,否则会抛出 IllegalMonitorStateException 异常。
  • 使用场景:主要用于线程间通信(如经典的“生产者-消费者”模型)。

3. Thread.yield()

  • 所属类java.lang.Thread(静态方法)
  • 作用:向操作系统的线程调度器发出一个“让步”暗示:当前线程愿意放弃当前分配到的 CPU 时间片。
  • 关于锁不会释放任何锁
  • 状态变化:调用 yield() 后,线程从“运行中(Running)”退回到“就绪状态(Ready)”(在 Java 线程状态中统称为 RUNNABLE)。
  • 注意点:这只是一个暗示(Hint),调度器完全可以忽略这个请求。即使让出了 CPU,该线程也可能立刻再次被操作系统选中执行。通常只让步于相同或更高优先级的线程。
  • 使用场景:极少在业务代码中使用,偶尔用于并发测试、调试,或者在自旋锁(Spinlock)中减少 CPU 消耗,防止一个线程长时间霸占 CPU。

4. Thread.join()

  • 所属类java.lang.Thread(实例方法)
  • 作用:让当前线程(调用 join() 所在的代码块的线程)陷入等待,直到目标线程(调用 join() 方法的那个线程对象)执行完毕
  • 关于锁join() 底层其实是调用了 Object.wait() 方法来实现的。它会释放当前 Thread 对象的锁,但不会释放当前线程所持有的其他业务对象的锁
  • 使用场景:用于处理线程间的依赖关系。例如,主线程需要等待子线程计算出结果后,才能继续往下执行汇总操作。

核心区别总结表

特性 Thread.sleep() Object.wait() Thread.yield() Thread.join()
所属类 Thread (静态方法) Object (实例方法) Thread (静态方法) Thread (实例方法)
是否释放锁 不释放 ("抱着锁睡觉") 释放锁 (必须在同步块中) 不释放 不释放外部锁 (底层调用wait,释放线程对象本身的锁)
必须在 synchronized 中使用?
唤醒条件 时间到 / 被中断 notify() / notifyAll() / 时间到 调度器重新分配时间片 目标线程执行结束
当前线程状态转变 RUNNABLE -> TIMED_WAITING RUNNABLE -> WAITING/TIMED_WAITING RUNNABLE -> RUNNABLE (Running -> Ready) RUNNABLE -> WAITING/TIMED_WAITING
主要设计目的 暂停当前线程执行 多线程间通信/协作 让出CPU时间片,避免过度占用 等待其他线程执行完毕

经典面试题:sleep()wait() 的区别?

这是最常被问到的对比,可以简单归纳为“三个不同”:

  1. 出处不同sleep()Thread 类的静态方法;wait()Object 类的实例方法。
  2. 对锁的处理不同(最核心)sleep() 不释放锁;wait() 释放锁。
  3. 使用位置和唤醒方式不同sleep() 可以在任何地方使用,靠时间自动唤醒;wait() 必须在 synchronized 代码块中使用,通常靠别人(notify)唤醒。
00:00
00:00