wait必须放在 synchronized 同步块中?为啥 wait() 在 Object 类里,sleep() 在 Thread 里?


一、为什么 wait() 必须放在 synchronized 同步块中?

❓先来个基本认知:

  • wait()线程之间通信的方法

  • 它会让当前线程进入等待状态,并且释放掉它持有的“锁”,等待其他线程通过 notify() 来唤醒它。


📌 重点:wait() 和 “锁” 是强相关的

举个例子你就明白了:

你有一个仓库(共享资源),有两个线程:

  • 消费者线程:来仓库取东西。

  • 生产者线程:往仓库放东西。

当消费者发现“仓库是空的”时,它要等生产者放货(即:wait)。
而生产者放货之后,会通知消费者“你可以来了”(即:notify)。

但是,如果这时候消费者没有获得锁就调用 wait() 会怎样?

new Object().wait(); // 直接抛异常 IllegalMonitorStateException!

因为你都没拿到钥匙(锁),你哪有资格说“我要在门口等着”(wait)?


✅ 所以为什么 wait() 要在同步块里?

因为:

  1. 只有拿到锁(进入了同步块),才有资格操作等待队列(wait/notify)

  2. 为了防止线程错过通知,必须让检查资源的代码和 wait() 之间是“原子操作”


💣 不加锁会出问题:Lost Wake-up(丢失通知)

比如:

if (count <= 0) {
   wait();
}

如果你在判断完 count <= 0 之后,还没来得及 wait(),CPU 就切换了线程,另一个线程把货放了,发了 notify(),你还没 wait 呢!

结果你这边一调用 wait(),就睡过去了,而通知早就发了——你永远也醒不过来了!

这就叫 丢失唤醒(Lost Wake-up),而加 synchronized 就能避免这个问题,因为你两步操作(检查条件、决定等待)是“加锁”的,别人进不来,线程切换时不会打断你。


二、为什么 sleep() 不需要在同步块中?

🤔 本质区别:

  • sleep() 是线程自己休息,和别人没关系。

  • 它不会释放锁、也不管什么等待队列,只是当前线程“自觉休息一下”。


举个例子:

A线程抢到了锁,执行中调用了 Thread.sleep(1000) ——它休息,但不释放锁

这时候 B线程来了,想进同步块,但没门,A线程还拿着钥匙。

所以:

sleep() 是线程自我暂停,不释放资源,不需要通知别人,也不管别人状态,当然就不需要同步块了。


三、总结对比表:

对比点wait()sleep()
定义位置ObjectThread
是否释放锁✅ 会释放锁❌ 不释放锁
是否需要同步块✅ 必须在 synchronized 中调用❌ 可以在任何地方调用
作用线程间通信,进入等待队列等待唤醒当前线程休息一会儿
唤醒机制需要其他线程调用 notify()时间到了自动醒来

四、额外回答:为啥 wait()Object 类里,sleep()Thread 里?

  • wait() 是操作对象锁(monitor)的,所以放在 Object 类中,每个对象都有锁。

  • sleep() 是操作线程自己的行为,所以属于 Thread 类。


📌 最通俗一句话总结:

wait()多人协作排队,必须“拉个队伍+发通知”,所以要锁;
sleep() 是“我先眯一会儿”,不管别人,也不让出门钥匙,自然不用锁。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值