notify为什么会引发超时,notify和notifyAll的区别
每个同步对象都有对应的monitor,首先了解下monitor的内部结构。
1.monitor结构
- Owner:指向拥有该同步对象的锁的线程,初始时为NULL
- WaitSet(等待池):包含之前持有过锁,但是调用wait方法释放掉锁的线程
- EntryList(锁池):包含当前正在竞争试图获取锁的线程
2.notify和notifyAll的区别
- 线程调用了wait()方法,便会释放锁,并进入等待池(WaitSet)中,不会参与锁的竞争。
- 调用notify()后,等待池(WaitSet)中的某个线程(只会有一个)会进入该对象的锁池(EntryList)中参与锁的竞争,若竞争成功,获得锁,竞争失败,继续留在锁池(EntryList)中等待下一次锁的竞争。
- 调用notifyAll()后,等待池(WaitSet)中的所有线程都会进入该对象的锁池(EntryList)中参与锁的竞争。
3.notify造成超时的原因
以生产者消费者案例为例:
- 现在有三个线程,生产者P1, 消费者C1和C2.开始运行的时候,三个都在锁池中等待竞争,假设C1抢到锁了,C1执行时由于没有资源可以消费 调用wait()方法,释放锁并进入等待池。
- C2抢到了锁,开始消费,同理,C2也进入了等待池。现在锁池里面只剩下了P1。
- P1获得了锁,开始生产,生产完成后,P1开始调用notify()方法唤醒等待池中的C1或者C2,然后P1调用wait()方法释放锁,并进入了等待池。
- 假设唤醒的是C1,C1进入锁池并获得锁,消费后notify()方法唤醒了C2,C2进入锁池,C1进入等待池,现在锁池中只有C1。
- C1获得了锁,发现没有任何资源可以消费,wait()后释放了锁,进入了等待池,现在三个线程全都在等待池,锁池中没有任何线程。导致无限等待!
notifyAll()后,不存在只唤醒同类线程的情况,故也就不会出现上述情况。
引用
https://juejin.cn/post/6844903801363628045
标签:锁池,notifyAll,线程,notify,C1,超时,等待 From: https://www.cnblogs.com/214txdy/p/17196700.html