Java Monitor
什么是 monitor(监视器)
monitor 是一种同步机制(别的编程语言也支持 monitor),允许线程拥有:
- 互斥:在 Java 虚拟机中,通过对象锁来支持,使多个线程能够独立地在共享数据上工作而不相互干扰;
- 协作:在 Java 虚拟机中,通过 Object 类的 wait 和 notify 方法来支持,使线程为一个共同的目标一起工作。
Java 中 monitor 的协作实现
Java 中 monitor的 协作实现依赖于两个概念:entry set 和 wait set。

Java 风格的 monitor 就像是一个大房间中包含了三个小房间,其中特殊房间(Special Room)每次只能有一个线程占用;也就是说,从一个人(线程)进入这个房间到它离开,它是独占这个房间里的所有数据。
既然是一个特殊房间,那么人就不可能随便进入,而是要等到这个房间中的人离开了,然后调度员会进行调度;而这些想进又进不去的人,都被集中在入口集(Entry Set)中等待,这时的线程状态为 BLOCKED。
JVM 中的调度器使用基于优先级的调度算法;如果两个线程有相同的优先级,会选择等待时间最长的线程,最后会遵循先进先出。
当然了,一个人有可能不能一直呆在特殊房间里,中途需要休息一下(调用 wait 方法),而等待集(Wait Set)就是让人休息的房间,这时的线程状态为 WAITING;当人休息好后(调用了 notify 方法)想要再进入特殊房间,那么它就还要经过入口集。
Java 中 monitor 的互斥实现
为了实现 monitor 的互斥功能,Java 虚拟机为每个对象关联了一个锁(内部锁,这把锁是一个实体),这个锁保存在对象头中。一个线程在获得锁和释放锁之间被称为拥有内部锁;如果一个线程获得了锁,那么在拥有锁的线程释放它之前,其他线程不能获得相同的锁。("锁定一个对象" 就是获得与该对象相关的 monitor。)
指的注意的是:对象锁也叫内部锁或 monitor 锁,API 文档规范通常把它简单地称为 "监视器"。
synchronized
这里不会讲关于 synchronized 的详细使用,请参照 synchronized 文章。
synchronized 是围绕内部锁实体构建的;在 Java 中 synchronized 的作用就是为了划分出一个监视区,每个监视区都与一个内部锁相关联。
Java 虚拟机中的线程在到达监控区域的开始时请求一个锁,在获得锁之前,线程不允许执行代码;一旦它获得了锁,线程就进入了受保护的代码块。当线程离开该块时,无论它是如何离开的,它都会释放相关对象上的锁。
内部锁在同步的两个方面都起作用:独占访问,建立对可见性至关重要的 happens-before。
wait() 和 notify()
在 Java 线程基础 的这篇文章中有对这两个方法如何使用的例子,而在这篇文章中主要针对这两个方法和 monitor 之间的关系做出解释。
为什么这两个方法只能写在 synchronized 方法或 synchronized 代码块中?因为 wait() 和 notify() 是 Java 中用于线程之间的通讯,使线程之间能够协作;简单的说就是实现了 monitor 的协作机制。
至于写在 Object 中,是为了让所有对象都关联一把内部锁。
总结
首先使用 synchronized 划分出一个监视区域,然后使用一个 monitor 来监视这个区域(每一个 Java 对象都关联一个 monitor),当一个线程执行到监控区域的开始时会先进入到 Entry Set,获得锁后会执行受保护代码块;如果调用 wait 则线程会进入到 Wait Set 并释放锁,当线程想要重新获取锁时还是要先进入 Entry Set。
内部锁在同步的两个方面都起作用:独占访问,建立对可见性至关重要的 happens-before。

浙公网安备 33010602011771号