什么是管程
java在1.5之前只提供了synchronized,wait,notfiy,notfiyAll3种实现并发的源语,他们实际上是管程的组成部分。
对应的英文是Monitor,他表示管理共享变量以及操作共享变量,使其支持并发的过程。
java的实现–MESA模式
在管程的发展史上出现过3中管程模型,Hasen、Hoare、MESA。java采用的是MESA模型
在并发变成领域,有俩大核心问题:互斥–一个共享资源同一时刻只能被一个线程访问;同步–即线程之间的通信、协作;
java的管程如何解决互斥问题
如果:
管程将资源以及方法都封装起来,只允许一个线程通过管程哦方法调用该方法。
java的管程如何解决同步问题
利用之前提到的消息-通知机制来让线程之间协作见下面的一个BlockQueue的代码,请忽略业务代码:P
- enq的时候while判断队列是否满了,如果满了,notFull.await()阻塞当前线程;
- enq如果没满,添加对象,并且用notEmpty.single()通知deque停止阻塞;
- deq可以顺利执行出队列的操作;
- deq的时候while判断队列是否为空,如果为空,notEmpty.await()阻塞当前线程;
- deq如果不为空,poll对象,并且用notFull.single()通知enq停止阻塞;
- enq可以顺利执行队列
1 | public class BlockQueue { |
notify使用场景
上面用了notify类似的逻辑,之前提到过能用notifyAll尽量用notifyAll。那么什么时候用notify呢。需要同时满足下面3个条件
- 所有线程的等待条件一样
- 所有线程满足等待条件后的操作一样
- 只需要唤醒一个线程
结合上面的场景,都是队列queue;notify之后的操作都是queue入队或者出队;只需要唤醒一个线程入/出队
管程3中模型的区别
- Hasen:T1在wait之后,T2notify,notify必须在T2最后一条语句,执行完后T2终止,以此保证系统只有一个线程在运行。
- Hoare:T1在wait之后,T2notify,notify后T2堵塞,T1开始运行,T1运行完后唤醒T2,新能略差,因为多了一次T2的唤醒。
- MESA:T1在wait之后,T2notify,T1值是获取了可执行的可能,需要竞争获取锁才能执行,JAVA采用此种模型
所以在MESA中wait的标准写法如下,因为被noyify通知之后线程只是可能执行,有可能在执行时候线程又会不满足条件
1 | while( 条件){ |