等待/通知的相关方法是任意Java对象都具备的,因为这些方法被定义在所有对象的超类java.lang.Object上:
等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()和notify/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。
先看单线程使用该机制:
通过实践结果看,生成一个消费一个。
再看多线程:
再执行一次:
多线程每次执行的结果似乎都不一样,也不是先生产后消费。wait和notify在此多线程应用不失效了?!从通知等待机制来分析,多线程的案例中6个线程分两组分别调用了对象myQueue中的wait()和notify(),相互交互。不应该出现失效的情况,为什么还是会出现消费者线程没有等到生产者的通知已生产完毕再进行消费的情况?
分析源代码,通知等待机制哪里失控了?首先分析消费者线程:
从源码看:消费者线程根据随机数获取消息队列中的数据。同时消息队列长度为0时wait(),除此以外都是根据随机数取数据。失控的点就在此处:如果消息队列长度不为0,比如说其长度为2,同时随机数为3,那么消费者线程取队列中的第4个数据——可想而知是没有任何元素在此处的。
综合上述,多线程并发如果只是有关键字synchronized,wait(),notify()等方法并不能完全保证业务逻辑的正确性即有效同步。怎么解决这个问题呢?还需要合理的业务逻辑:
以上可以得出一个小经验:提炼出等待/通知的经典范式,该范式分为两部分,分别针对等待方(消费者)和通知方(生产者)。
等待方遵循如下原则:
1)获取对象的锁。
2)如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件。
3)条件满足则执行对应的逻辑。
对应的伪代码如下:
synchronized(对象) {
while(条件不满足) {
对象.wait();
}
对应的处理逻辑
}
通知方遵循如下原则:
1)获得对象的锁。
2)改变条件。
3)通知所有等待在对象上的线程。
对应的伪代码如下:
synchronized(对象) {
改变条件
对象.notifyAll();
}