为什么wait、notify必须在synchronized保护的同步代码中

先思考如果wait、notify不在synchronized保护的同步代码中的样子:

//经典的生产者与消费者
public class BlockingQueue{

   Queue<String> buffer=new LinkedList<String>();

   //负责往buffer中添加数据,添加完后执行notify唤醒之前等待的线程。
   public void give(String data){
 
        buffer.add(data);
        
        notify();  
   }




   // 负责检查整个buffer是否为空,如果为空,就等待;否则,就取出一个数据。
   public String take()  throws InterruptedException{

        while(buffer.isEmpty()){
             wait();
        }

        return buffer.remove; 
   }
}

 以上代码没有受synchronized保护,可能会发生以下情况:

  • 首先,消息者线程调用take()方法并判断buffer.isEmpty方法是否返回true,为true代表buffer是空的,则线程进入等待状态。但是在线程调用wait方法之前,就被调度器暂停了,而此时还未来得及执行wait方法
  • 其次,生产者执行整个give方法,并执行了notify方法,但是没有任何效果,因为take()方法的wait还没有执行。
  • 再次,执行被调度器暂停的消费者线程,继续执行wait方法,等待中。因为 buffer.isEmpyt、wait,即判断与执行不是一个原子操作,它在中间被打破了,是线程不安全的。
  • 最后,如果此时没有更多的生产者进行生产,那么消费者便可能陷入无穷的等待中,因为其刚才错过了notify方法。

因此,应该在两个方法前加synchronized关键字,获得对象的锁monitor。 否则,抛出IllegalMonitorStateException异常,wait、notify间也存在潜在的竞态条件。

 

参考:

https://zhuanlan.zhihu.com/p/138770887

https://blog.youkuaiyun.com/youanyyou/article/details/107310028

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值