在接触并发之前,我只听说过进程、线程,管程这个词倒是头回听说,抱着认真好学的态度,去找了找关于 管程 的资料,不学不知道,原来并发里的两大难题--互斥和同步都可以用管程来解决,可以说,管程是一把解决并发的万能钥匙。
那什么是管程呢?原来管程并不像进程、线程这样来形容一个特指东西的名词,管程是指管理共享变量以及读共享变量的操作过程,让他们支持并发。Java 中的 Monitor,我们经常将它翻译成 “监视器”,其实它还有个更学术的名字就是管程。
管程有三种模型,其中广泛应用的是 MESA 模型,Java 管程实现参考的也是 MESA 模型,所以我就着重学习这个模型。前面提到了管程可以解决并发领域互斥和同步的两大核心问题,下面我们先看看管程是如何解决互斥问题的。
互斥问题的解决
互斥指的同一时刻只允许有一个线程访问共享资源,管程解决互斥问题的思路很简单,就是将共享变量及对共享变量的操作统一都封装起来,如图:
线程 A 和线程 B 如果想访问共享变量 queue,只能通过管程提供的入队和出队操作,入队和出队操作保证互斥性,只允许一个线程进入,而对外暴露的就只有管程,看上去有点面向对象封装的意思。
同步问题的解决
在管程解决互斥问题的解决方案中,我们看到了其实共享变量和对共享变量的操作都是被封装起来的,要想访问共享变量就要访问管程,所以同步的解决办法就是在管程的入口添加一个等待队列,当多线程想同时进入管程内部时,只允许一个线程进入,其他线程在等待队列中等待。
进入到管程内部,有可能执行修改共享变量的方法还有条件,比如要执行入队操作,必须保证队列不满;要执行出队操作,必须保证队列不空,管程对每个条件的变量还对应有一个等待队列,如图:
这里的入口等待队列与条件等待队列是完全不同的两个队列,当进入管程内部的线程因执行方法的条件不满足会进入条件等待队列,等待被其他线程唤醒,唤醒后会重新进入入口的等待队列,竞争资源。
Java 内置的管程
Java 内置管程与 MESA 模型类似,在 MESA 模型中,条件变量可以有多个, Java 语言内置的管程里只有一个条件变量。
Java 内置的管程方案就是 syncronized ,使用 syncronized 修饰的代码块,在编译器会自动生成相关加锁和解锁代码,但是只会支持一个条件变量。
总结一下 :
以上是管程的相关介绍,后续我们会进入 Java JUC 工具包的学习,看看除了 syncronized 其他强大的并发编程类都有哪些独特的用处。
☞ 这里有一篇 关于JUC 的入门说明
感兴趣的同学可以浏览一下哦~