关注公众号 JavaStorm 解锁更多并发java
在吃透 Syncchronized 原理 中介绍了关于 Synchronize
的实现原理,不管是同步方法仍是同步代码块,不管是ACC_SYNCHRONIZED
仍是monitorenter
、monitorexit
都是基于Monitor
实现的,那么这篇来介绍下什么是Monitor。编程
所谓管程:指的是管理共享变量以及对共享变量的操做过程,让它们支持并发。翻译为 Java 就是管理类的成员变量和成员方法,让这个类是线程安全的。安全
是一种程序结构,结构内的多个子程序(对象或模块)造成的多个工做线程互斥访问共享资源。这些共享资源通常是硬件设备或一群变量。管程实现了在一个时间点,最多只有一个线程在执行管程的某个子程序。与那些经过修改数据结构实现互斥访问的并发程序设计相比,管程实现很大程度上简化了程序设计。 管程提供了一种机制,线程能够临时放弃互斥访问,等待某些条件获得知足后,从新得到执行权恢复它的互斥访问。数据结构
在管程的发展史上,前后出现过三种不一样的管程模型,分别是:Hasen
模型、Hoare
模型和 MESA
模型。其中,如今普遍应用的是 MESA
模型,而且 Java
管程的实现参考的也是 MESA
模型。因此今天咱们重点介绍一下MESA
模型。并发
在并发领域,有两个核心问题:一个是互斥,一个是同步。管程就是来解决这两个问题的。ui
它的思路很简单,将共享变量以及对共享变量的操做统一封装起来。以下图所示,管程 A 将共享变量 data 和相关的操做入队enq()
、出队deq()
封装起来。线程 A 和线程 B想访问共享变量 data ,只能经过调用管程提供的 enq()
和 deq()
。固然前提是 enq()
、deq()
保证互斥性,只容许一个线程进入管程。是否是颇有面向对象的感受。spa
在管程模型里,共享变量和对共享变量的操做是被封装起来的,图中最外层的框就表明封装的意思。框的上面只有一个入口,而且在入口旁边还有一个入口等待队列。当多个线程同时试图进入管程内部时,只容许一个线程进入,其余线程则在入口等待队列中等待。这个过程相似就医流程的分诊,只容许一个患者就诊,其余患者都在门口等待。线程
管程里还引入了条件变量的概念,并且每一个条件变量都对应有一个等待队列,以下图,条件变量 A 和条件变量 B 分别都有本身的等待队列。翻译
经过条件通知去唤醒等待队列的线程竞争 锁资源。设计
咱们经过一段代码说明,实现一个阻塞队列,队列分别有出队与入队,都是要先获取互斥锁,就像管程中的入口。
notFull.await();
。notEmpty.await();
。notEmpty
对应的等待队列。notFull
对应的等待队列。public class BlockedQueue<T>{
final Lock lock = new ReentrantLock();
// 条件变量:队列不满
final Condition notFull = lock.newCondition();
// 条件变量:队列不空
final Condition notEmpty = lock.newCondition();
// 入队
void enq(T x) {
lock.lock();
try {
while (队列已满){
// 等待队列不满
notFull.await();
}
// 省略入队操做...
// 入队后, 通知可出队
notEmpty.signal();
}finally {
lock.unlock();
}
}
// 出队
void deq(){
lock.lock();
try {
while (队列已空){
// 等待队列不空
notEmpty.await();
}
// 省略出队操做...
// 出队后,通知可入队
notFull.signal();
}finally {
lock.unlock();
}
}
}
复制代码
在这段示例代码中,咱们用了 Java 并发包里面的 Lock 和 Condition,若是你看着吃力,也不要紧,后面咱们还会详细介绍,这个例子只是先让你明白条件变量及其等待队列是怎么回事。须要注意的是:await() 和前面咱们提到的 wait() 语义是同样的;signal() 和前面咱们提到的 notify() 语义是同样的。管程经过条件队列通讯实现了同步,为咱们 Java中的并发编程提供了基本支持。
关注公众号 JavaStorm 获取更多并发原理