Java线程间通信之wait/notify(2)

cookThread--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--饺子还没好,等待厨师通知...
cookThread
--饺子好啦,厨师休息会儿
waiterThread
--服务员把饺子端给客人了
waiterThread
--打烊收工,服务员回家
cookThread
--打烊收工,厨师回家

执行结果

 运行机制

我们来了解下wait/notify的运行机制,借用《并发编程的艺术》中的一个图

可能有人会对所谓监视器(monitor),对象锁(lock)不甚了解,在此简单解释下:

  jvm为每一个对象和类都关联一个锁,锁住了一个对象,就是获得了对象相关联的监视器。

  只有获取到对象锁,才能拿到监视器,如果获取锁失败了,那么线程就会进入阻塞队列中;如果成功拿到对象锁,也可以使用wait()方法,在监视器上等待,此时会释放锁,并进入等地队列中。

  关于锁和监视器的区别,园子里有个哥们的文章写得很详细透彻,在此引用一下,有兴趣的童鞋可以了解一下锁和监视器之间的区别 - Java并发

根据上面的图我们来理一下具体的过程

  1.首先,waitThread获取对象锁,然后调用wait()方法,此时,wait线程会放弃对象锁,同时进入对象的等待队列WaitQueue中。

   2.notifyThread线程抢占到对象锁,执行一些操作后,调用notify()方法,此时会将等待线程waitThread从等待队列WaitQueue中移到同步队列SynchronizedQueue中,waitThread由waitting状态变为blocked状态。需要注意的时,notifyThread此时并不会立即释放锁,它继续运行,把自己剩余的事儿干完之后才会释放锁。

  3.waitThread再次获取到对象锁,从wait()方法返回继续执行后续的操作。

  4.一个基于等待/通知机制的线程间通信的过程结束

至于notifyAll则是在第二步中将等待队列中的所有线程移到同步队列中去。

避免踩坑

  在使用wait/notify/notifyAll时有一些特别留意的,在此再总结一下:

    1.一定在synchronized中使用wait()/notify()/notifyAll(),也就是说一定要先获取锁,这个前面我们讲过,因为只有加锁后,才能获得监视器。否则jvm也会抛出IllegalMonitorStateException异常。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/bc2b6059675b09c5e93375f3c4421125.html