管程:并发编程的万能钥匙

Java 语言在 1.5 之前,提供的唯一的并发原语就是管程,而且 1.5 之后提供的 SDK 并发包,也是以管程技术为基础的。

管程:管理共享变量以及对共享变量的操作过程,让它们支持并发。

MESA 模型

先后出现过三种不同的管程模型,分别是:Hasen 模型、Hoare 模型和 MESA 模型。其中,现在广泛应用的是 MESA 模型,并且 Java 管程的实现参考的也是 MESA 模型。

并发两大核心问题:

  1. 互斥:同一时刻只允许一个线程访问共享资源
  2. 同步:线程之间如何通信、协作

image

管程的组成锁和0或者多个条件变量,java用两种方式实现了管程

  1. synchronized+wait、notify、notifyAll
    只支持一个条件变量,即wait,调用wait时会将其加到等待队列中,被notify时,会随机通知一个线程加到获取锁的等待队列中;可重入锁;支持非公平锁

  2. lock+内部的condition
    相对synchronized支持中断和增加了时间的等待,lock需要自己进行加锁解锁,更加灵活;;可重入锁;支持公平和非公平锁。

MESA 管程wait编程范式

需要在一个 while 循环里面调用 wait()

while(条件不满足) {
  wait();
}

原因

MESA 管程里面,T2 通知完 T1 后,T2 还是会接着执行,T1 并不立即执行,仅仅是从条件变量的等待队列进到入口等待队列里面。这样做的好处是 notify() 不用放到代码的最后,T2 也没有多余的阻塞唤醒操作。但是也有个副作用,就是当 T1 再次执行的时候,可能曾经满足的条件,现在已经不满足了,所以需要以循环方式检验条件变量。

Hasen:执行完,再去唤醒另外一个线程。故notify需要放函数最后。
Hoare:中断当前线程,唤醒另外一个线程,执行玩再去唤醒。
MESA:进入入口等待队列,不一定能执行。

条件变量等待队列和入口等待队列

wait设置超时后,只是从条件变量等待队列到了入口等待队列。

posted @ 2023-03-18 16:26  kiper  阅读(76)  评论(0编辑  收藏  举报