java并发编程实战管程.pdf
08|管程:并发编程的
2019-03-16
00:0012:01
讲述:讲述:讲述:大小:11.02M大小:11.02M大小:11.02M
并发编程这个技术领域已经发展了半个世纪了,相关的理论和技术纷繁复杂。那有没有一种
技术可以很方便地解决我们的并发问题呢?这个问题如果让我选择,我一定会选择管程技术。
Java语言在1.5之前,提供的唯一的并发原语就是管程,而且1.5提供的SDK并发包,也
是以管程技术为基础的。除此之外,C/C++、C#等高级语言也都支持管程。
可以这么说,管程就是一把解决并发问题的。
什么是管程
不知道你是否曾思考过这个问题:为什么Java在1.5之前仅仅提供了synchronized关键字及
wait()、notify()、notifyAll()这三个看似从天而降的方法?在刚接触Java的时候,我以为它会
提供信号量这种编程原语,因为操作系统原理课程告诉我,用信号量能解决所有并发问题,结果
我发现不是。后来我找到了:Java采用的是管程技术,synchronized关键字及wait()、
notify()、notifyAll()这三个方法都是管程的组成部分。而管程和信号量是等价的,所谓等价指的
是用管程能够实现信号量,也能用信号量实现管程。但是管程更容易使用,所以Java选择了管
管程,对应的英文是Monitor,很多Java领域的同学都喜欢将其翻译成“监视器”,这是直
译。操作系统领域一般都翻译成“管程”,这个是意译,而也更倾向于使用“管程”。
所谓管程,指的是管理共享变量以及对共享变量的操作过程,让他们支持并发。翻译为Java领
域的语言,就是管理类的成员变量和成员方法,让这个类是线程安全的。那管程是怎么管的呢?
MESA模型
在管程的发展史上,先后出现过三种不同的管程模型,分别是:Hasen模型、Hoare模型和
MESA模型。其中,现在广泛应用的是MESA模型,并且Java管程的实现参考的也是MESA
模型。所以今天我们重点介绍一下MESA模型。
在并发编程领域,有两大问题:一个是互斥,即同一时刻只允许一个线程共享资源;另
一个是同步,即线程之间如何通信、协作。这两大问题,管程都是能够解决的。
我们先来看看管程是如何解决互斥问题的。
管程解决互斥问题的思路很简单,就是将共享变量及其对共享变量的操作统一封装起来。在下图
中,管程X将共享变量queue这个队列和相关的操作入队enq()、出队deq()都封装起来了;
线程A和线程B如果想共享变量queue,只能通过调用管程提供的enq()、deq()方法来实
现;enq()、deq()保证互斥性,只允许一个线程进入管程。不知你有没有发现,管程模型和面向
对象高度契合的。估计这也是Java选择管程的吧。而我面章节介绍的互斥锁用法,其
背后的模型其实就是它。
管程模型的代码化语义
那管程如何解决线程间的同步问题呢?
这个就比较复杂了,不过你可以借鉴一下我们曾经提到过的就医流程,它可以帮助你快速地理解
这个问题。为进一步便于你理解,在下面,我展示了一幅MESA管程模型示意图,它详细描述了
MESA模型的主要组成部分。
在管程模型里,共享变量和对共享变量的操作是被封装起来的,图中最外层的框就代表封装的意
思。框的上面只有一个,并且在旁边还有一个等待队列。当多个线程同时试