【管程模型-互斥】:synchronized原理

什么是管程?

所谓管程,指的是管理共享变量以及对共享变量的操作过程,让他们支持并发。用java来说,管理一个类的成员变量和成员方法,使之成为线程安全的类。

synchronized关键字和wait(),notify()和notifyall()都是管程的组成部分。

管程模型-MESA 模型

在这里插入图片描述
在并发编程领域,有两大核心问题:一个是互斥,即同一时刻只允许一个线程访问共享资源;另一个是同步,即线程之间如何通信、协作。看管程模型MESA是如何解决并发问题的。

  1. 解决互斥问题:
    当多个线程同时试图进入管程内部时,只允许一个线程进入,其他线程则在入口等待队列中等待。
  2. 解决同步问题:
    该管程模型中还引入条件变量的概念,而且每个条件变量都有一个等待队列。当线程执行期间满足条件变量A,释放锁对象,进入相应的条件变量等待队列中,等待被唤醒,再次添加到入口等待队列中。
管程模型的区别

在管程发展史上,出现三种不同的管程模型,分别是:Hasen模型,Hoare模型,MESA模型,java的管程参考的就是这个模型。
管程要求同一时刻只允许一个线程执行,那三个模型的区别就是当T1唤醒(notify)T2等待的线程(wait),那究竟是T1执行呢还是T2执行?

  • Hasen 模型,notify()放在代码的最后面,这样在唤醒T2线程后,T1也就执行完了,然后T2再执行,这样就能保证同一时刻只有一个线程运行。
  • Hoare模型,T1唤醒了T2,T1陷入阻塞,T2马上执行,T2执行完,再唤醒T1,这样也能保证同一时刻只有一个线程运行。相比Hasen模型,T1多了一个阻塞唤醒的操作。
  • MESA模型,结合上面的MESA模型图,T1唤醒T2,并不马上执行T2,而是把T2从条件变量等待队列中放到入口等待队列中,T1继续执行。
    好处:1.motify不用放到代码最后,2.也没有多余的唤醒阻塞情况
    坏处:当T2在次执行时,可能曾经满足的条件,现在不满足了,所以要以循环方式检验条件变量。

注意:因为再次放到入口等待队列中,期间条件变量是不确定的,需要再次判断条件变量是否满足,所以wait()方法需要

while(条件不满足) {
  wait();
}
简易版 MESA 模型synchronized

JAVA参考MESA模型,java内置管程模型synchronized对MESA模型做了精简。
MESA模型条件变量可以有多个,synchronized条件变量只有一个,请看下图
在这里插入图片描述
如果此时你还是优点不懂一个条件变量个两个条件变量的区别,上代码,来展示一下

  1. 使用java SDK并发包中LOCK实现多个条件变量
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();
    }  
  }
}

2.使用synchronized实现一个条件变量

class Allocator {
	private String demo;
    // 经典写法
    while(demo==null){
      try{
        wait();
      }catch(Exception e){
      }   
    } 
  }
  // 归还资源
  synchronized void free(
  if(demo!=null){
    notifyAll();
  }
}

其实:总结来说MESA管程,

  1. 就是管程保证只有一个线程在方法中执行,其他等待线程放入入口等待队列中,
  2. 添加条件变量,可以判断进入方法体中,当前状态是否满足,满足就往下执行,不满足,可以wait(),
  3. 放入条件变量等待队列中,若在某时刻该条件变量满足了,就notify,把该线程从条件变量等待队列中放入入口等待队列中,等待本次线程执行结束,从入口等待队列中取出一个线程从上次等待的代码继续放下执行,
  4. 因为是从上次执行的代码出开始往下执行,同时因为是等待线程结束可能条件变量又会发生变化,所以wait需要while循环。

参考:极客时间
更多:邓新

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值