关键字
锁通信
wait
notify
我们知道java线程一共有6种状态,分别是NEW
、RUNABLE
、BLOCKED
、WAITING
、TIMED_WATING
、TERMINATED
。而线程之前的状态切换,其中一个方式就是靠wait()、notify()机制实现。
wait/notify机制
类似一种生产者-消费者模型。 当一个线程在获取到资源的锁后,发现该资源不满足使用条件,就会调用wait()
方法,等待该资源满足条件后再继续执行。 而notify()
则类似生产者,如果资源满足条件了,则通过调用notify(),随机的唤醒一个之前等待的线程,通知其条件已满足,可以继续执行。
定义
wait()
notify()
是Object类中的两个本地方法。对于wait()方法,解释如下:
我们假设一个资源为object。如果一个线程调用了资源object的wait()方法,那么将会发生如下事情:
- 线程进入到object的
等待队列(wait set)
,使自身由runable变为了waiting状态。 - 释放持有的object锁。
- 等待其他线程调用object的notify、notifyAll方法才会被再次唤醒。
唤醒之后,线程则又变为可调度状态,然后需要同其他线程再次去竞争object资源的锁。一旦获取到锁之后,线程就会完全恢复,继续从object.wait()
之后的代码开始执行。
由于我们一般是因为不满足某些条件,才会调用wait方法等待,因此在线程恢复执行后,我们总是应该再次去check一下条件是否满足。这是因为这样,我们总是在一个循环中触发wait()方法,类似:
synchronized (obj) {
while (<条件不满足>)
obj.wait(timeout);
... // 条件已满足,开始执行相应的业务逻辑
}
notify方法则是用来从object的等待队列里,随机的唤醒一个线程。被唤醒的线程再去竞争获取object的锁,然后继续执行。
整个运作机制可以简单用下图来表示:
![](https://img.haomeiwen.com/i7676544/63730f3a75269ef8.png)
说明
无论是wait()还是notify(),其执行的前提条件都是:该线程首先持有资源对象object的锁。否则的话,就会抛出IllegalMonitorStateException异常。
wait(long timeout)
:和wait()方法类似的还有一个wait(long timeout),如果线程一直没有被唤醒,当超时时间到了,就会自动被唤醒。
notifyAll()
:notify()方法,也对应有一个notifyAll()方法,该方法会将等待队列里的所有线程都唤醒,唤醒后的线程行为和notify()保持一致。
事实上一个线程被唤醒的方式包括以下几种:
- 其他线程调用object的notify()方法, 而该线程刚好被从等待队列中选中.
- 其他线程调用了notifyAll()方法。
- 其他线程通过interrupt中断了该线程。
- 等待超时时间到达,线程被自动唤醒。
刚刚上文也提到了执行notify和wait,必须先获取到资源对象的锁,获取锁的方式有三种:
- 执行对象的同步方法。
- 执行对象的同步代码块。
- 对于类对象,执行类的静态同步方法。
参考文献
https://www.jianshu.com/p/9ac697c166f3
https://www.jianshu.com/p/1dafbf42cc54
网友评论