1. 简介
在本教程中,我们将学习什么是监视器以及如何在 Java 中使用它。
2. 什么是监视器?
监视器是一种同步机制,允许线程具有:
- 互斥 – 只有一个线程可以使用锁在某个时间点执行该方法
- 合作 – 使用等待集使线程等待满足某些条件的能力
为什么此功能称为“监视器”?因为它监视线程如何访问某些资源。
监视器在70年代初正式成为P.B.汉森撰写的名为“共享类”的论文中感兴趣的主题。之后,C.A.R. Hoare撰写了论文《监视器 – 一种操作系统结构概念》,其中他进一步发展了监视器的概念。该论文介绍了一种同步形式,并提出了使用信号量的实现模型。
3. 监控功能
监视器为并发编程提供了三个主要功能:
- 一次只有一个线程对关键代码段具有互斥访问权限
- 监视器中运行的线程在等待满足某些条件时可能会被阻止
- 一个线程可以在满足其他线程正在等待的条件时通知它们
4. Java如何实现监视器?
临界区是通过不同线程访问相同数据的代码的一部分。
在 Java 中,我们使用sync关键字来标记关键部分。我们可以使用它来标记方法(也称为同步方法)甚至更小的代码部分(同步语句)。
对于支持哪种方法存在相反的意见 - 方法同步通常是推荐的更简单的方法,而从安全角度来看,同步语句可能是更好的选择。
在 Java 中,监视器与每个对象或类之间存在逻辑连接。因此,它们涵盖了实例方法和静态方法。互斥是通过与每个对象和类关联的锁完成的。此锁是称为互斥锁的二进制信号量。
4.1. 建筑和专属房间类比
Java 对监视机制的实现依赖于两个概念——条目集和等待集。在文献中,作者使用建筑物和专属房间的类比来表示监视器机制。在这个类比中,一次只能有一个人出现在一个专属房间中。
所以,在这个类比中:
- 监视器是一栋包含两个房间和一个走廊的建筑
- 同步的资源是“独占房间”
- 等候套装是“等候室”
- 入口设置是“走廊”
- 线程是想要进入专属房间的人
当这个人想进入专属房间时,他首先去走廊(入口集),在那里他等待调度员。因此,调度员将挑选此人并将他送到专属房间。
JVM 中的调度程序使用基于优先级的调度算法。如果两个线程具有相同的优先级,JVM 将使用 FIFO 方法。
因此,当调度程序选择此人时,他会进入专属房间。可能是这个房间里发生了一些特定的情况,所以那个人需要出去等待专属房间再次可用。因此,该人最终将进入候诊室(等候集)。因此,调度程序将安排此人稍后进入专属房间。
此外,重要的是要提到线程在此过程中经历的步骤,使用相同的类比:
- 进入建筑物 – 进入监视器
- 进入专属房间 – 获取监视器
- 在专属房间 – 拥有监视器
- 离开专属房间 – 释放监视器
- 离开建筑物 – 退出监视器。
幸运的是,Java在后台完成大部分工作,我们在处理多线程应用程序时不需要编写信号量。因此,我们唯一需要做的就是用同步的关键字包装我们的关键部分,它就会立即成为一个监视区域。
4.2.wait()和notify()
wait() 和notify() 是 Java 中用于同步块的关键方法,可实现线程之间的协作。
wait() 命令调用线程释放监视器并进入睡眠状态,直到其他线程进入此监视器并调用notify()。此外,notify() 唤醒在特定对象上调用wait() 的第一个线程。
5. 结论
在本文中,我们讨论了监视器的概念,然后解释了它在 Java 中的实现。
正如我们所了解的,它是隐藏在同步关键字后面的核心同步机制。它依赖于等待集和条目集,我们通过一个简单的类比解释了它是如何工作的。
我们还提到了等待和通知方法的使用。