Skip to content

Sleep 和 Wait 的区别

Sleep(Thread.sleep())

一、是什么?

Thread.sleep()Thread 类的静态方法,使当前线程暂停执行指定时间(毫秒/纳秒),不释放锁,时间结束后自动恢复运行。

二、解决什么问题

解决需要让线程暂停执行一段时间的场景(如模拟延迟、定时任务),但不影响其他线程对共享资源的访问(因为不释放锁)。

三、核心方法

java
Thread.sleep(long millis); // 毫秒
Thread.sleep(long millis, int nanos); // 毫秒+纳秒

四、应用场景

  1. 模拟网络请求延迟
  2. 定时轮询(如每隔 5 秒检查状态)
  3. 控制动画帧率(游戏开发)

五、Java 示例

java
public class SleepExample {
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (SleepExample.class) {
                System.out.println("Thread 1: 持有锁,休眠 2 秒");
                try {
                    Thread.sleep(2000); // 休眠但不释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 1: 唤醒");
            }
        }).start();

        new Thread(() -> {
            synchronized (SleepExample.class) {
                System.out.println("Thread 2: 获得锁"); // 需等待 Thread 1 释放锁
            }
        }).start();
    }
}

六、重要注意事项

  1. 必须捕获 InterruptedException
  2. 是静态方法,作用于当前线程
  3. 不释放锁,其他线程无法进入同步块

Wait(Object.wait())

一、是什么?

Object.wait()Object 类的方法,使当前线程释放锁并进入等待状态,需通过 notify()/notifyAll() 唤醒。

二、解决什么问题

解决线程间协作问题(如生产者-消费者模型),让线程在条件不满足时主动释放锁,避免资源浪费。

三、核心方法

java
object.wait(); // 无限等待
object.wait(long timeout); // 超时等待

四、应用场景

  1. 生产者-消费者队列(缓冲区空/满时等待)
  2. 线程池任务调度
  3. 多线程条件检查(如等待初始化完成)

五、Java 示例

java
public class WaitExample {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 1: 等待通知...");
                try {
                    lock.wait(); // 释放锁并等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 1: 收到通知,继续执行");
            }
        }).start();

        Thread.sleep(1000); // 确保 Thread 1 先执行
        
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 2: 发送通知");
                lock.notify(); // 唤醒等待线程
            }
        }).start();
    }
}

六、重要注意事项

  1. 必须在 synchronized 块中调用
  2. 唤醒后需重新竞争锁
  3. 使用 while 循环检查条件(避免虚假唤醒)

Sleep 和 Wait 的核心区别

特性SleepWait
所属类ThreadObject
锁释放❌ 不释放锁✅ 释放锁
调用要求任意场景必须在 synchronized 块中
唤醒方式超时后自动唤醒notify()/notifyAll() 唤醒
使用场景单纯的时间延迟线程间协作
异常捕获必须捕获 InterruptedException必须捕获 InterruptedException

总结

  • sleep 当需要纯暂停:不涉及线程协作,只是让当前线程“睡一会”(如倒计时)。
  • wait 当需要线程协作:涉及共享资源条件判断(如队列空/满),需释放锁让其他线程工作。
  • 关键区别sleep 是“抱着锁睡觉”,wait 是“释放锁等人叫醒”。实际开发中,wait 通常与同步机制配合使用,而 sleep 更适用于独立延迟任务。
  • JDK 8+ 提示:优先考虑 java.util.concurrent 包的工具(如 SemaphoreCountDownLatch)替代裸 wait/notify,减少错误风险。