管程:指的是管理共享变量以及对共享变量的操作过程,让他们支持并发。
Java在1.5之前仅仅提供了synchronized关键字及wait(),notify(),notifyAll()这三个方法。而操作系统原理介绍信号量能解决所有并发问题,结果我发现不是。Java采用管程技术,synchronized,wait,notify,notifyAll做为管程的组成部分。管程和信号量是等价的,所谓等价就是用信号量能够解决的问题,用管程也能够解决。
并发编程领域,有两大核心问题:一个是互斥,即同一时刻只允许一个线程访问共享资源;另一个是同步,即线程之间如何通信,协作。
管程模型里,共享变量和对共享变量的操作都是被封装起来的。在管程的发展史上,先后出现过三种不同的管程模型:Hasen模型,Hoare模型,MESA模型。Java管程实现参考的是MESA模型。如下图所示:
最外层的框就代表封装的意思。当多个线程同时试图进入管程内部时,只允许一个线程进入,其它线程则在入口等待队列中等待。
管程里还引入了条件变量的概念,而且每个条件变量都对应一个等待队列。
那条件变量和等待队列的作用?
Hasen模型,Hoare模型,MESA模型一个核心区别就是当条件变量满足后,如何通知相关线程。管程要求同一时刻只允许一个线程执行,那当线程T2的操作使线程T1等待条件满足时,T1和T2究竟谁可以执行呢?
Hasen模型:要求notify放在代码的最后,这样T2通知完后,T2就结束了,然后T1再执行,这样就保证了同一个时刻只有一个线程执行。
Hoare模型:T2通过完T1后,T2阻塞,T1马上执行;等T1执行完,再唤醒T2,也能保证同一个时刻只有一个线程执行。相比Hasen模型,T2多了一次阻塞唤醒操作。
MESA模型:T2通知完T1后,T2还是会接着执行,T1并不立即执行,仅仅是从条件变量的等待队列进到入口等待队列里面。这样做的好处:notify不需要放到代码最后,T2也没有多余的阻塞唤醒操作。坏处:就是当T1再次执行的时候,可能曾经满足的条件,现在已经不满足了,所以需要以循环方式检验条件变量。











网友评论