Java 中 wait()sleep() 的主要区别如下:

1. 基本定义

wait() 方法

  • wait()Object 类的方法
  • 用于线程间通信,让线程释放对象锁并等待
  • 必须在同步代码块或同步方法中调用
  • 需要配合 synchronized 关键字使用

sleep() 方法

  • sleep()Thread 类的静态方法
  • 用于让线程暂停执行指定时间
  • 可以在任何地方调用
  • 不需要同步环境

2. 核心区别对比表

特性 wait() sleep()
所属类 Object 类 Thread 类
调用方式 实例方法 静态方法
锁释放 ✅ 释放对象锁 ❌ 不释放锁
使用环境 必须在 synchronized 中 任何地方
唤醒方式 notify()/notifyAll() 或超时 超时自动唤醒
异常处理 检查异常 InterruptedException 检查异常 InterruptedException
线程状态 WAITING/TIMED_WAITING TIMED_WAITING
用途 线程间通信 线程休眠

3. 详细对比

3.1 锁的释放

public class LockReleaseDemo {
    private static final Object lock = new Object();
    
    public static void main(String[] args) {
        // wait() 释放锁
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread1: 获取锁");
                try {
                    System.out.println("Thread1: 调用 wait(),释放锁");
                    lock.wait();  // 释放锁,进入等待状态
                    System.out.println("Thread1: 被唤醒,重新获取锁");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        
        // sleep() 不释放锁
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread2: 获取锁");
                try {
                    System.out.println("Thread2: 调用 sleep(),不释放锁");
                    Thread.sleep(2000);  // 不释放锁
                    System.out.println("Thread2: sleep 结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

3.2 使用环境

public class UsageEnvironmentDemo {
    private static final Object lock = new Object();
    
    // wait() 必须在 synchronized 中使用
    public void waitExample() {
        synchronized (lock) {
            try {
                lock.wait();  // ✅ 正确
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    // wait() 不在 synchronized 中会抛出异常
    public void waitErrorExample() {
        try {
            lock.wait();  // ❌ 运行时抛出 IllegalMonitorStateException
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    // sleep() 可以在任何地方使用
    public void sleepExample() {
        try {
            Thread.sleep(1000);  // ✅ 正确
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    // sleep() 也可以在 synchronized 中使用
    public void sleepInSyncExample() {
        synchronized (lock) {
            try {
                Thread.sleep(1000);  // ✅ 正确,但不释放锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3.3 唤醒方式

public class WakeupDemo {
    private static final Object lock = new Object();
    
    public static void main(String[] args) {
        // 等待线程
        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("等待线程: 开始等待");
                try {
                    lock.wait();  // 等待被唤醒
                    System.out.println("等待线程: 被唤醒了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        // 唤醒线程
        Thread notifyingThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    Thread.sleep(1000);  // 确保等待线程先执行
                    System.out.println("唤醒线程: 准备唤醒");
                    lock.notify();  // 唤醒等待线程
                    System.out.println("唤醒线程: 已发送唤醒信号");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        waitingThread.start();
        notifyingThread.start();
    }
}

3.4 超时等待

public class TimeoutDemo {
    private static final Object lock = new Object();
    
    public static void main(String[] args) {
        // wait() 带超时
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread1: 开始等待,最多3秒");
                try {
                    lock.wait(3000);  // 等待3秒后自动唤醒
                    System.out.println("Thread1: 等待结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        
        // sleep() 带超时
        new Thread(() -> {
            System.out.println("Thread2: 开始休眠3秒");
            try {
                Thread.sleep(3000);  // 休眠3秒后自动唤醒
                System.out.println("Thread2: 休眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

4. 实际应用场景

4.1 wait() 的典型应用 - 生产者消费者模式

public class ProducerConsumerDemo {
    private static final int MAX_SIZE = 5;
    private static final List<Integer> buffer = new ArrayList<>();
    private static final Object lock = new Object();
    
    // 生产者
    static class Producer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                synchronized (lock) {
                    while (buffer.size() >= MAX_SIZE) {
                        try {
                            System.out.println("缓冲区满,生产者等待");
                            lock.wait();  // 缓冲区满时等待
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    
                    buffer.add(i);
                    System.out.println("生产: " + i + ",当前大小: " + buffer.size());
                    lock.notifyAll();  // 通知消费者
                }
                
                try {
                    Thread.sleep(100);  // 模拟生产耗时
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    // 消费者
    static class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                synchronized (lock) {
                    while (buffer.isEmpty()) {
                        try {
                            System.out.println("缓冲区空,消费者等待");
                            lock.wait();  // 缓冲区空时等待
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    
                    int value = buffer.remove(0);
                    System.out.println("消费: " + value + ",当前大小: " + buffer.size());
                    lock.notifyAll();  // 通知生产者
                }
                
                try {
                    Thread.sleep(200);  // 模拟消费耗时
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public static void main(String[] args) {
        new Thread(new Producer()).start();
        new Thread(new Consumer()).start();
    }
}

4.2 sleep() 的典型应用 - 模拟耗时操作

public class SleepDemo {
    // 模拟网络请求
    public static String fetchDataFromServer() {
        try {
            System.out.println("开始请求数据...");
            Thread.sleep(2000);  // 模拟网络延迟
            System.out.println("数据请求完成");
            return "模拟数据";
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();  // 恢复中断状态
            return null;
        }
    }
    
    // 定时任务
    public static void scheduledTask() {
        while (true) {
            System.out.println("执行定时任务: " + new Date());
            try {
                Thread.sleep(5000);  // 每5秒执行一次
            } catch (InterruptedException e) {
                System.out.println("定时任务被中断");
                break;
            }
        }
    }
    
    // 限流控制
    public static void rateLimitedRequest(int requestCount) {
        for (int i = 0; i < requestCount; i++) {
            System.out.println("发送请求 " + (i + 1));
            try {
                Thread.sleep(1000);  // 每秒最多1个请求
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    
    public static void main(String[] args) {
        // 示例1:模拟网络请求
        String data = fetchDataFromServer();
        System.out.println("获取到的数据: " + data);
        
        // 示例2:限流控制
        rateLimitedRequest(3);
    }
}

5. 线程状态变化

5.1 wait() 的状态变化

RUNNING → synchronized块 → 调用wait() → WAITING状态
                                              ↓
                                        notify()/notifyAll()
                                              ↓
                                        获取锁 → RUNNABLE → RUNNING

5.2 sleep() 的状态变化

RUNNING → 调用sleep() → TIMED_WAITING状态
                           ↓
                     超时时间到
                           ↓
                     RUNNABLE → RUNNING

6. 最佳实践

6.1 wait() 的最佳实践

public class WaitBestPractices {
    private final Object lock = new Object();
    private boolean condition = false;
    
    // ✅ 正确的 wait() 使用方式
    public void correctWaitUsage() {
        synchronized (lock) {
            // 使用 while 循环检查条件,防止虚假唤醒
            while (!condition) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    // 处理中断
                    return;
                }
            }
            // 执行业务逻辑
        }
    }
    
    // ❌ 错误的 wait() 使用方式
    public void incorrectWaitUsage() {
        synchronized (lock) {
            if (!condition) {  // 应该使用 while
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    // 正确的 notify() 使用方式
    public void correctNotifyUsage() {
        synchronized (lock) {
            condition = true;
            lock.notifyAll();  // 优先使用 notifyAll()
        }
    }
}

6.2 sleep() 的最佳实践

public class SleepBestPractices {
    
    // ✅ 正确的 sleep() 使用方式
    public void correctSleepUsage() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // 恢复中断状态
            Thread.currentThread().interrupt();
            // 处理中断逻辑
            System.out.println("线程被中断");
        }
    }
    
    // ❌ 错误的 sleep() 使用方式
    public void incorrectSleepUsage() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();  // 只是打印异常,不处理中断
        }
    }
    
    // 使用 TimeUnit 提高可读性
    public void readableSleep() {
        try {
            TimeUnit.SECONDS.sleep(1);  // 比 Thread.sleep(1000) 更清晰
            TimeUnit.MILLISECONDS.sleep(500);
            TimeUnit.MINUTES.sleep(1);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

7. 常见面试题

Q1: 为什么 wait() 要在 synchronized 中调用?

A:

  • wait() 需要释放对象锁,只有持有锁的线程才能释放锁
  • 如果不在 synchronized 中调用,会抛出 IllegalMonitorStateException
  • 这是为了确保线程安全,防止竞争条件

Q2: wait() 和 sleep() 都会抛出 InterruptedException,如何处理?

A:

  • 捕获异常后应该恢复线程的中断状态:Thread.currentThread().interrupt()
  • 根据业务需求决定是继续执行还是退出
  • 不要简单地忽略中断异常

Q3: 为什么推荐使用 while 循环检查 wait() 的条件?

A:

  • 防止虚假唤醒(spurious wakeup)
  • 确保条件真正满足后才继续执行
  • 避免因意外唤醒导致的逻辑错误

Q4: notify() 和 notifyAll() 有什么区别?

A:

  • notify(): 随机唤醒一个等待线程
  • notifyAll(): 唤醒所有等待线程
  • 推荐使用 notifyAll(),避免线程饥饿问题

8. 总结

方面 wait() sleep()
核心用途 线程间通信 线程休眠
锁处理 释放锁 不释放锁
使用场景 需要协调的并发场景 简单的延时控制
复杂度 较复杂,需要配合同步 简单,直接调用
推荐使用 生产者消费者、条件等待 定时任务、限流控制

选择原则

  • 需要线程间协调通信 → 使用 wait()
  • 只需要简单的延时 → 使用 sleep()
  • 在同步环境中需要等待条件 → 使用 wait()
  • 在任何地方需要暂停 → 使用 sleep()

理解两者的区别对于编写正确的并发程序至关重要,合理使用可以有效解决线程同步和协调问题。

Logo

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

更多推荐