继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

面试高频考点:说说 wait、notify、notifyAll 的区别与用法

我就是渣哥
关注TA
已关注
手记 92
粉丝 1
获赞 3

原文来自于:https://zha-ge.cn/java/91

面试高频考点:说说 wait、notify、notifyAll 的区别与用法

敲代码这么多年,某天刚踏进公司楼下,一只咖啡猫就拦住了我(这年头什么都能拦人),问我:
“老铁,Java wait, notify, notifyAll 傻傻分不清楚,到底咋回事啊?”

哈,巧了,这不就说到我初入江湖的黑历史吗?给你摆一道——那个和多线程死磕的夜晚。


一切都从多线程开始

那会儿刚学会 synchronized 还没焐热,领导就甩来个“生产者-消费者”,说让线程轮流搞点活。
一看题眼儿,得,多线程通信。那就来点简单的 synchronized + wait()/notify() 吧!

肾上腺素飙升,撸代码如行云流水:

synchronized(lock) {
    while (!ready) { 
        lock.wait(); 
    }
    // ...
    lock.notify();
}

结果,代码上线一试,嗯?“偶尔”死锁。队友还怪我业务水平不行。差点背锅把公司锅都端走。
那时候的我,以为 notify() 是万能钥匙,结果分分钟被多线程打脸。


它们到底有啥不同?

总结你常见的使用方法,三兄弟的“家族谱”大概长这样:

  • wait():我先挂起,有事叫我,自动释放锁。
  • notify():随机叫醒一个等着的,有种拼手气的既视感。
  • notifyAll():算了,全叫起来,大家别睡了。

如果把它们比作一个咖啡屋里的吃瓜群众:

  1. wait():你自觉排队进休息区,不捣乱(释放锁)。
  2. notify():老板随机敲敲窗户,让某个正在闭眼养神的家伙回到工作岗位。
  3. notifyAll():老板直接拉闸放电,所有趴着的人都站起来。

踩坑瞬间

讲真,真要被坑才记得住。我的两个经典坑:

  • 坑1:没在 synchronized 里用 wait/notify — JVM直接崩溃吐槽
    IllegalMonitorStateException,甭问,就是没加锁。大多数人都中过招。

  • 坑2:notify 唤醒的是“谁都行”
    假设有多个不同身份的线程(比如甲是生产、乙是消费)。用 notify() 唤醒,结果你想让消费者干活,唤醒的却是另一个生产者……呵,尴尬到飞起,然后一片沉默。


那用法就是“就这么简单”?

也不是,说点实在的:

  • “wait/notify”必须在 synchronized(或对应的 Lock)里,不然 JVM 秒甩异常。
  • 有好几个“等通知”的线程,notify 可能漏掉你想要唤醒的那一个!「比如一窝生产者全被唤醒,发现都‘不合适’又滚回去了。」
  • 用循环+wait防止“伪唤醒”:
    线程从 wait 回来,有可能不是收到通知,而是被操作系统“洗个澡”叫醒(俗称虚假唤醒)。
synchronized(lock){
    while (条件不满足) {
        lock.wait();
    }
    // 走到这里安全了!
}
  • 如果追求“万无一失”或者太懒,一个 notifyAll() 保平安,不过性能可能不是最优

经验启示

下面是我的 避坑速查表,面试答题和实战两不误:

永远配合 synchronized:
wait/notify/notifyAll 这仨不是万能遥控器,必须要在同步块(或者 Lock 条件队列)里才能调,不然 JVM 会给你来个 IllegalMonitorStateException,当场下课。

循环包裹 wait:
千万别写 if,要写 while。原因就是“虚假唤醒”这事儿实打实存在,线程可能在没被通知的情况下就醒了。用 while 能让它醒来后再确认条件。

notify 慎用:
如果你控制的线程身份单一(比如全是消费者),notify() 还能用。可要是生产者 + 消费者搅和在一起,光靠 notify() 十有八九会唤错人,浪费一次调度机会。

notifyAll 更保险:
面试答题时说清楚:“notifyAll 牺牲点性能,但能避免遗漏”。这话八股味很浓,HR 听了点头。实战里,如果不追求极限性能,notifyAll 通常更稳。

生产者-消费者模式里:
一般做法是“生产者唤醒消费者,消费者唤醒生产者”。要想保证逻辑闭环,notifyAll 可能更适合,因为你无法精准知道“此刻哪类线程在等”。

面试官杀手锏问题

问:那为什么要用 while 包着 wait,而不是 if?

答法:

if 只能检查一次条件,虚假唤醒或者别的线程篡改条件后,会直接往下走,导致错误。

while 会反复检查,直到条件满足才执行,保证逻辑安全。

一听你这么答,面试官心里估计会加个 ✔️。

最后来总结一下

wait:老实蹲着,条件没满足就不干活,还顺手把锁让出去。

notify:随手叫醒一个,效率高但容易“叫错人”。

notifyAll:全体起立,别睡了,虽然有点吵。

它们仨就是多线程通信里的“电话亭”,打电话要在锁里打,接通了还得确认对方是谁。

别小看这些细节,面试里能扯出一大堆花活,写代码时却常常能救命。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP