notify为什么会引发超时,notify和notifyAll的区别

notify为什么会引发超时,notify和notifyAll的区别

每个同步对象都有对应的monitor,首先了解下monitor的内部结构。

1.monitor结构

Snipaste_2023-03-08_23-01-07.jpg

  • Owner:指向拥有该同步对象的锁的线程,初始时为NULL
  • WaitSet(等待池):包含之前持有过锁,但是调用wait方法释放掉锁的线程
  • EntryList(锁池):包含当前正在竞争试图获取锁的线程

2.notify和notifyAll的区别

  • 线程调用了wait()方法,便会释放锁,并进入等待池(WaitSet)中,不会参与锁的竞争。
  • 调用notify()后,等待池(WaitSet)中的某个线程(只会有一个)会进入该对象的锁池(EntryList)中参与锁的竞争,若竞争成功,获得锁,竞争失败,继续留在锁池(EntryList)中等待下一次锁的竞争。
  • 调用notifyAll()后,等待池(WaitSet)中的所有线程都会进入该对象的锁池(EntryList)中参与锁的竞争。

3.notify造成超时的原因

以生产者消费者案例为例,其中缓冲区大小为1:

  1. 现在有三个线程,生产者P1, 消费者C1和C2.开始运行的时候,三个都在锁池中等待竞争,假设C1抢到锁了,C1执行时由于没有资源可以消费 调用wait()方法,释放锁并进入等待池。
  2. C2抢到了锁,开始消费,同理,C2也进入了等待池。现在锁池里面只剩下了P1。
  3. P1获得了锁,开始生产,生产完成后,P1开始调用notify()方法唤醒等待池中的C1或者C2,然后P1调用wait()方法释放锁,并进入了等待池。
  4. 假设唤醒的是C1,C1进入锁池并获得锁,消费后notify()方法唤醒了C2,C2进入锁池,C1进入等待池,现在锁池中只有C1。
  5. C1获得了锁,发现没有任何资源可以消费,wait()后释放了锁,进入了等待池,现在三个线程全都在等待池,锁池中没有任何线程。导致无限等待!

notifyAll()后,不存在只唤醒同类线程的情况,故也就不会出现上述情况。

引用

https://juejin.cn/post/6844903801363628045

posted @ 2023-03-08 23:25  のNice  阅读(266)  评论(0编辑  收藏  举报