作为一名java程序员,相信都知道wait/notify的通知机制可以用来实现线程间通信。
求职面试时,不少公司都会出类似这样的题目。笔者有次面试时,面试官就问了这样一个问题:
wait/notify/notifyAll一般适用于什么场景?
由于笔者之前对这个知识点没有重视,面试官调侃说,你对WaitNotify通知机制都没有掌握,难怪你期望薪资那么低。
我们知道,wait表示线程的等待,调用该方法会导致线程阻塞,直至另一线程调用notify或notifyAll方法才可另其继续执行。经典的生产者、消费者模式即是使用wait/notify机制得以完成。
在了解wait/notify通知机制前,我们先回顾下java线程的生命周期。
今天我们针对此知识点,来编写个例子加深理解。
假设我开了一家水果实体店,日常经营主要有两项,一项是进货,一项是卖货。需要满足如下条件:
往店里进货,前提是店里库存不足,如果库存充足,则无需进货,直到把货卖出去了。卖货,前提店里库存充足,库存不足时就要进货。
新建个水果店抽象类AbstractFruitStore
水果实体店类实现AbstractFruitStore
生产者Producer
消费者Consumer
运行结果:
从中我们可以得出,Wait-Notify场景一般和下面3个因素相关:
状态变量(StateVariable)当线程需要wait时,是因为一些条件得不到满足导致的。例如往队列里填充数据,当队列元素已经满时,线程就需要wait停止运行。当队列元素有空缺时,再继续自己的执行。条件断言(ConditionPredicate)当线程确定是否进入wait或者是从notify醒来的时候是否继续往下执行,大部分都要测试状态条件是否满足。条件队列(ConditionQueue)每个对象都有一个内置的条件队列,当一个线程在该对象锁上调用wait函数的时候,就会将该线程加入到该对象的条件队列中。总结
如果线程调用了Object对象的wait()方法,那么线程会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。当有线程调用了Object对象的notify()方法(只随机唤醒一个wait线程)或是notifyAll()方法(唤醒所有wait线程)被唤醒的的线程会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,只有线程再次调用wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了synchronized代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
一个知识点不仅能考验求职者的对该知识点的掌握程度,还延伸出其他知识点,考验求职者的知识面,难怪阿里百度这样的大公司喜欢在面试时拿它来考验求职者。
由于笔者水平有限,文中纰漏之处在所难免,权当抛砖引玉,不妥之处,请大家批评指正。
-END-
作者:洪生鹏擅长java、Android、qt、小程序平台开发。