【Java】wait notify 为什么放在同步块内

wait、notify和notifyAll三个方法必须放在同步块内执行。

现象:

如果不放在同步块内,运行时会抛出这个异常:
IllegalMonitorStateException。

原因:

因为wait和notify(包括notifyAll,为了方便,后面仅写notify)的使用一般而言,都是成对的(自己等待,通知别人)。

举一个生产者消费者的例子,大概是下面这样的模式:

生产者producer:

if full

   wait;

else 

  produce;

  notify consumer;

消费者consumer:

if empty

  wait

else  

  do consume;

  notify producer;

如果消费者或者生产者的逻辑不放在同步块内,那么整个生产或者消费就不是原子性的操作,那么可能会有这样的问题:

比如说生产者先判断full,那么准备执行wait,但是此时线程切换到了消费者,消费者执行消费,并且notify。随后又切换到了生产者线程,此时由于消费者消费了,那么就不是full了,生产者本应该生产,但是却继续执行了wait,等于说之前的一次notify丢失了。

回顾一下这个过程,本质上是因为wait和notify的操作不是同步执行导致的。所以,wait和notify执行前必须拿到锁才行,这就是需要放到同步块内执行的原因。

最后,打开wait方法的源码:

     * <pre>
     *     synchronized (obj) {
     *         while (&lt;condition does not hold&gt;)
     *             obj.wait();
     *         ... // Perform action appropriate to condition
     *     }
     * </pre>

作者建议wait的调用应该始终用如上形式:

1.同步;

2.while判断条件,而不是if;

同步的原因上面已经解释过了。为什么要用while?

这是因为,如果线程数不止一个,比如消费者和生产者都有多个线程,那么notify后,只有一个线程可以执行,其余的线程仍然需要wait,此时就必须用while保证可以重新while。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值