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

什么是管程

管程是一种解决并发的概念,和信号量是等价的,管程能够去实现信号量,信号量也能实现管程

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

Java中的synchronized、wait()、notify()、notifyAll()就是用管程去实现的。

MESA模型

在管程发展史中,一共出现过三种模型:Hasen模型、Hoare模型、MESA模型。现在广泛应用的就是MESA模型,Java管程的实现也是参考的MESA模型。

在并发领域有两个核心问题:

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

这两个问题管程都是可以解决的。

管程解决互斥问题

管程将共享变量以及对共享变量的操作统一封装起来,对共享变量的操作都提供线程安全的方法。管程的模型和面向对象高度契合,就是利用封装的方法,把一个线程不安全的类封装成线程安全的。

管程解决同步问题 

管程解决同步问题使用了条件变量的概念,每个条件变量都有一个等待队列。

 

图中, 最外层的框就相代表对共享变量的操作的封装。当一个线程想去操作共享变量时,如果有其他的线程正在执行,就必须进入入口等待队列,这个入口的控制就是互斥。对应于现实相当于就医流程中的排队挂号。

当线程进入管程(临界区)后,如果某个条件不满足时,就会进入条件变量的等待队列,然后其他线程时允许进入管程的。比如你去找医生做检查,医生需要你的验血报告,条件不满足,你需要去做验血报告,其他人可以继续去找医生就医。

等条件满足时,会再次进入入口的等待队列。

await()方法就是进入等待队列。

notify()、notifyAll()表示满足条件。

举个例子:实现一个线程安全的队列

public class BlockedQueue<T>{
  final Lock lock =
    new ReentrantLock();
  // 条件变量:队列不满  
  final Condition notFull =
    lock.newCondition();
  // 条件变量:队列不空  
  final Condition notEmpty =
    lock.newCondition();

  // 入队
  void enq(T x) {
    lock.lock();
    try {
      while (队列已满){
        // 等待队列不满 
        notFull.await();
      }  
      // 省略入队操作...
      //入队后,通知可出队
      notEmpty.signal();
    }finally {
      lock.unlock();
    }
  }
  // 出队
  void deq(){
    lock.lock();
    try {
      while (队列已空){
        // 等待队列不空
        notEmpty.await();
      }
      // 省略出队操作...
      //出队后,通知可入队
      notFull.signal();
    }finally {
      lock.unlock();
    }  
  }
}

wait() 的正确姿势

但是有一点,需要再次提醒,对于 MESA 管程来说,有一个编程范式,就是需要在一个 while 循环里面调用 wait()。这个是 MESA 管程特有的

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

因为当条件满足时,线程只是重新进入入口队列等待运行,在真正运行到的时候,条件可能又不满足了,所有需要用while循环判断条件是否满足

hasen 是执行完,再去唤醒另外一个线程。能够保证线程的执行。hoare,是中断当前线程,唤醒另外一个线程,执行玩再去唤醒,也能够保证完成。而mesa是进入等待队列,不一定有机会能够执行。

notify() 何时可以使用

还有一个需要注意的地方,就是 notify() 和 notifyAll() 的使用,前面章节,我曾经介绍过,除非经过深思熟虑,否则尽量使用 notifyAll()。那什么时候可以使用 notify() 呢?需要满足以下三个条件:

  •  所有等待线程拥有相同的等待条件;
  • 所有等待线程被唤醒后,执行相同的操作;
  • 只需要唤醒一个线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值