第21章 – 并发 – 线程之间的协作 object的wait()与notify()和notifyAll()
线程之间的协作 object的wait()与notify()和notifyAll()
1. 这些方法只能在 同步控制方法(synchronized修饰的方法)或同步块(synchronized修饰代码块)
中调用. 非同步方法或非同步块中调用,代码可以编译通过,但执行时抛IllegalMonitorStateException
因为调用这些对象时,必须要事先获取对象的锁.
2. 调用wait()之后,立刻释放锁, 当前线程挂起(就相当于CPU暂时不管这个线程,不分配这个线程执行时间了)
当前现场挂起后,等待notify()或notifyAll()发信号,一旦等到了信号,就重新唤醒(相当于CPU又开始管这个线程了)
因为wait()是在synchronized中,所以wait()之后再次被唤醒的,还需要争抢锁.如果没有抢到锁,一般还是要继续
挂起的,所以wait()一般需要放到while(感兴趣的条件)这样的循环中的.
3. 调用 notify()或 notifyAll() 只是给wait()的线程发信号,唤醒一个线程. 但是notify()或 notifyAll()并不释放锁.
只有在用synchronized 包裹的的代码(包含 notify()或 notifyAll() )全部执行完之后,才释放锁.释放锁之后,被唤醒
的线程有一个能抢到锁,然后继续执行wait()之后的代码.
4. 错失的信号(p706)
T1:
synchronized(sharedMonitor)
{
<setup condition for T2> //将someCondition变成false
sharedMonitor.notify();
}
T2:
while(someCondition)
{
//Point1
synchronized(sharedMonitor)
{
sharedMonitor.wait();
}
}
上述有问题的写法,发生问题的场景
(1)前提是: T2尚未调用wait(),初始someCondition为true
(2)产生的问题是:T2不能按预期正常工作,导致T2无限期wait(),目的是someCondition为false时,T2唤醒(离开wait())
(3)问题分析:假设某一时刻,T2开始执行,并且someCondition为true,导致执行到Point1处,此时线程
调度器可能切换到T1的<setup condition for T2>时将someCondition设置为false,然后调用notify()后,
调度器再次切换到T2的Point1之后,此时实际上someCondition为false了,而T2中已经来不及了,继续执行
sharedMonitor.wait();导致T2无限期执行下去(因为T1的notify只执行一次).
(4)问题修改:使用下面的代码替换T2
synchronized(sharedMonitor)
{
while(someCondition)
{
sharedMonitor.wait();
}
}
修改后,假如T1首先执行,则执行后将someCondition改成false,当执行T2时并不会进入wait().
假如T2首先执行,则因为初始someCondition为true,T2进入wait(),然后T1开始执行,T1中notify
后,T2被再次唤醒,再次执行while后,不会wait了(以为T1中将someCondition设置为false)
5. notifyAll()因为某个特定的锁而被调用时,只有等待这个锁的任务才会被唤醒,并不是唤醒所有等待的线程.(p707)
赞 赏微信赞赏 支付宝赞赏
本文固定链接: https://www.jack-yin.com/coding/thinking-in-java/2148.html | 边城网事
【下一篇】每日一句- The night’s silence, like a deep lamp, is burning with the light of its milky way.