Java并发监视器-Monitor

一、阅读本文须知

  • 信号量(Semaphore):在多线程环境下使用的一种设施,可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。
  • 互斥量(Mutex):又称为互斥锁,每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

二、Monitor的特性

  • 互斥:Monitor 最重要的特点是,同一个时刻,只有一个 线程能进入 monitor 中定义的临界区,这使得 monitor 能够达到互斥的效果。
  • 信号量:仅仅有互斥的作用是不够的,无法进入 monitor 临界区的线程,它们应该被阻塞,并且在必要的时候会被唤醒。显然,monitor 作为一个同步工具,也应该提供这样的管理线程状态的机制。想想我们为什么觉得 信号量 和 互斥 在编程上容易出错,因为我们需要去亲自操作变量以及对 线程 进行阻塞和唤醒。monitor 这个机制之所以被称为“更高级的原语”,是因为它对外屏蔽掉了这些机制,使得使用 monitor 的人看到的是一个简洁易用的接口。

三、实现Monitor的三要素

1、临界区
2、monitor 对象及锁
3、条件变量以及定义在 monitor 对象上的 wait、signal 操作。

  • 互斥:使用 monitor 机制的目的主要是为了互斥进入临界区,为了做到能够阻塞无法进入临界区的线程,需要通过一个基于互斥量的锁和一个 monitor object 来协助完成,这个 monitor object 内部会有相应的数据结构,例如列表,来保存被阻塞的线程。
  • 信号量:为了在适当的时候能够阻塞和唤醒线程,需要引入一个条件变量用来决定什么时候是“适当的时候”,这个条件可以来自程序代码的逻辑,也可以是在 monitor object 的内部,总而言之,程序员对条件变量的定义有很大的自主性。不过,由于 monitor object 内部采用了数据结构来保存被阻塞的队列,因此它也必须对外提供两个 API 来让线程进入阻塞状态以及之后被唤醒,分别是 wait 和 notify。

四、Java中Monitor的实现

1、临界区:被 synchronized 关键字修饰的方法、代码块,就是 monitor 机制的临界区。
2、monitor 对象及锁:synchronized 关键字在使用的时候,往往需要指定一个对象与之关联,例如 synchronized(this),synchronized 如果修饰的是实例方法,那么其关联的对象实际上是 this,如果修饰的是类方法,那么其关联的对象是 this.class。总之,synchronzied 需要关联一个对象,而这个对象就是 monitor object。
3、条件变量以及定义在 monitor 对象上的 wait、signal 操作:
wait、signal 操作:java.lang.Object 类定义了 wait(),notify(),notifyAll() 方法
条件变量:Java 对象存储在内存中,分别分为三个部分,即对象头、实例数据和对齐填充,而在其对象头中,保存了锁标识,wait、signal 操作会改变条件进而改变锁标识的状态

注:本文所有内容仅供参考,如有错误,还望指出

猜你喜欢

转载自blog.csdn.net/peanutwzk/article/details/105834100