专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java并发编程必知:wait()与sleep()的6大核心区别及实战避坑指南

temp10 2025-09-12 03:00:12 java教程 4 ℃ 0 评论

从一道面试题看并发编程的"拦路虎"

"Wait 和 Sleep 有什么区别?"这道题是不是让你挠头? 就像餐厅等位时,有人占着座位玩手机(sleep()),有人把座位让给别人去候客区等叫号(wait())——看似都是"等",但背后的逻辑天差地别!今天咱们用3个真实案例+2张对比表,把这对"孪生兄弟"彻底讲明白,让你面试再也不慌!

核心区别对比:6大维度吃透底层差异

一张表看懂核心差异

1. 所属类与调用方式

  • wait():是Object类的方法(所有对象都有!),必须在synchronized同步块里调用,比如:
  • synchronized(lock) { lock.wait(); // 正确姿势 }
  • 要是敢在同步块外调用?立马给你抛IllegalMonitorStateException异常!
  • sleep():是Thread类的静态方法,直接Thread.sleep(1000)就能用,不需要锁!

2. 锁处理机制:最核心的区别!

这是面试官最爱问的点!划重点:

Java并发编程必知:wait()与sleep()的6大核心区别及实战避坑指南

  • sleep():睡觉都抱着锁不放! 比如线程拿着锁睡1秒,其他线程只能干等着。
  • wait():会主动释放锁,让其他线程有机会干活。就像上厕所要先出来才能让别人进~

3. 唤醒机制:被动通知 vs 主动起床

  • wait():得靠别人叫醒!要么其他线程调用notify(),要么等超时(比如wait(3000)等3秒)。
  • sleep():到点自动醒,不需要别人管。适合定时任务,比如每小时刷新缓存。

4. 线程状态变化

  • wait():进入WAITING状态,被唤醒后要重新抢锁
  • sleep():进入TIMED_WAITING状态,醒了直接继续跑

使用场景深度解析:该用哪个?怎么选?

场景1:生产者-消费者模型(必须用wait()!)

比如电商订单系统,生产者(下单线程)和消费者(处理线程)要协作:

  • 库存满了?生产者wait()释放锁,等消费者处理完再notify()唤醒
  • 库存空了?消费者wait(),等生产者补货到了再唤醒

核心代码就5行:

synchronized(queue) {
    while(queue.isEmpty()) queue.wait(); // 没货就等
    Object data = queue.poll();
    queue.notifyAll(); // 通知生产者补货
}

场景2:定时任务(用sleep()更简单)

比如每30分钟刷新一次缓存,用sleep()一行搞定:

while(true) {
    refreshCache();
    Thread.sleep(30*60*1000); // 睡30分钟
}

简单直接,不用处理复杂的锁机制~

3个实战坑点,90%的人都踩过!

坑点1:用if判断条件(虚假唤醒问题)

错误示范:

if(queue.isEmpty()) { // 千万别用if!
    queue.wait(); 
}

正确做法是用while循环:

while(queue.isEmpty()) { // 循环检查,防止假唤醒
    queue.wait(); 
}

因为线程可能被"虚假唤醒"(操作系统的bug),必须再检查一遍条件!

坑点2:捕获异常后不恢复中断状态

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    // 必须加这句!否则上层代码不知道被中断了
    Thread.currentThread().interrupt(); 
}

坑点3:wait和notify用了不同的锁对象

// 错误示范!
synchronized(lock1) { lock1.wait(); } // 等lock1的通知
synchronized(lock2) { lock2.notify(); } // 却通知lock2的线程

记住:必须用同一个锁对象!就像你在A群@人,那人得在A群才能收到~

大厂真实案例:这俩方法怎么用?

案例1:阿里电商订单系统

双11高峰期,用wait()实现订单队列削峰:

  • 订单太多处理不过来?让生产者线程wait()
  • 消费者处理完一批就notifyAll()唤醒生产者
    这样既不会把系统累死,又能充分利用资源!

案例2:定时缓存刷新(sleep()版)

某支付系统用sleep()实现每分钟刷新汇率缓存:

new Thread(()->{
    while(true) {
        loadExchangeRate(); // 加载汇率
        Thread.sleep(60*1000); // 睡1分钟
    }
}).start();

简单粗暴但有效,适合这种独立任务~

总结:一句话记住区别

需要协作通信用wait()(释放锁等通知),单纯延时用sleep()(抱着锁睡大觉)

思考题:这段代码会输出什么?

Object lock = new Object();
new Thread(()->{
    synchronized(lock) {
        lock.wait(1000);
        System.out.println("A");
    }
}).start();
Thread.sleep(500);
synchronized(lock) {
    lock.notify();
}

你在项目中踩过wait/sleep的坑吗?欢迎评论区分享经验! 觉得有用记得点赞收藏,下次面试不迷路~

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表