临界区、管程、信号量介绍

2024-06-04 03:48
文章标签 介绍 信号量 管程 临界

本文主要是介绍临界区、管程、信号量介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

临界区、管程、信号量是操作系统对并发编程支持的三个概念。它们并不是属于java,而是属于操作系统(目前我知道 linux有这三个概念,我觉得windows也应该有只是不确定,否则怎么会支持多核CPU呢?)。

临界区

临界区是线程需要互斥执行的一段代码。临界区的资源是线程共享的,但是执行的返回结果是不确定的。 举个例子:linux系统中的fork()命令会开启一个子线程,每个子线程都应该去调用父线程的方法返回一个PID。假设这个方法是:

NEW_PID = next_pid++

上面的next_pid就是临界资源,是多个线程共享的, 这段代码不是原子操作,但是一定要是互斥的。 临界区只是一个概念,具体实现要看编程语言还操作系统。

信号量

信号量也是一个编程概念,基本由一个整数变量,和两个原子操作组成。这两个原子操作对这个整数变量对行增加和删除。成功才执行后面的代码,失败则阻塞。 具体代码实现可以看我的另一篇博客。
https://blog.csdn.net/u011296165/article/details/80249229

管程

管程对应的英文是Monitor。管程的定义是管理共享变量以及对共享变量的操作过程,让它们支持并发。相对应的java语意是管理java类的成员变量和成员方法,让这个类是线程安全的。
管程是编程语言提供的一种抽象数据结构,它有两个特点

  1. 互斥访问,即任一时刻只有一个线程在执行管程代码;
  2. 正在管程内的线程可以放弃对管程的控制权;
    条件变量(condition variable)是管程内部的实现机制,每个条件变量都代表一种等待的原因,也对应一个等待队列。条件变量有两个操作:wait和signal。这两个条件变量的操作,是某种情况下等待和在某种情况下执行。

MESA模型----java管程使用的模型

管程实现互斥

管程实现互斥就是将共享变量和对共享变量操作的方法封闭起来。如下图,管程X将共享变量queue这个队列和相关操作入队enq()和deq()都封装起来。线程A和线程B如果想要访问共享变量queue()队列,就要使用enq()和deq()方法,enq()和deq()保持了互斥性,这样来保证线程安全。

管程实现同步

MESA的模型图
在这里插入图片描述

图中最大的方框就代表封装的意思, 上方开口就是管程的入口, 入口旁边有一个等待队列。一个管程只能有一个线程去执行,其他线程就进入到这个等待队列。 就像是去医院看医生,一个医生只能同时给一个病人看病,其他拿到号的病人都会在门外等着。

管程里面还有一个条件变量的概念,管程里面还有一个条件变量的概念,管程里面还有一个条件变量的概念这一定非常重要。 后面的东西都是使用了这个条件变量。每一个条件变量都有自己的等待队列,就如图上的条件变量A和条件变量B有两个等待队列。

现在对他的执行过程做一个说明。我们管程中通常两个方法,方法X代表出队操作,方法Y代表入队操作。我们的共享变量V就是队列。我们的假设线程T1在执行方法X出队操作,那么在执行这个出队操作之前是不是应用有一个前置条件,判断这个共享变量V队列不能为空。 而这个前置条件就是条件变量。条件变量的等待队列就是无法获取条件的时候,条件变量执行了wait()方法,将线程放入到了这个条件变量的等待队列中了。
举个生活中的例子:小明去医院看医生,第一步、进医院的就是去取号,然后去对应医生办公室门口等待叫号。这一步对应的就管程入口等待对列第二步 叫到号之后医生让小明去拍X光片,他就去抽血处排队抽血。这一步对应的就是条件变量等待对列第三步 抽完血之后,小明又要去医生办公室门口等待叫号,这一步对应的就是当条件变量符合执行条件就从条件变量队列中释放,但并不是马上去执行,而是去管程入口队列中等待。第四步,小明进入医生办公室看医生,医生让小明在去验上血。小明就要去验血处等待。这一步对应的就是当线程第二次进入管程中,发现条件变量又不符合了,又要去重新进入条件变量队列中重新等待条件符合要求。 当符合要求后在次进入管程入口等待队列,直到进入管程后条件符合要求去执行方法完成。
这里可能有点绕,还请多看几遍。
下面用代码做一下示范。
假定对象A代表“队列不空”这个条件,那么线程进入管程需要判断队列是否为空,如果为空则调用 A.wait()方法。同理当“条件 不空”这个条件满足时,线程T2需要调用 A.notify()来通知A等待队列中的一个线程。 也可以调用 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();}  }
}
  1. 对于入队操作,如果队列已满。就需要等待直接队列不满,所以这就用notFull.await()。
  2. 对于出队操作,如果队列为空,就需要等待直接到队不空,所以这就用notEmpty.await()。
  3. 如果入队成功,那么队列就不空,就需要通知队列不空的等待队列。这里就要用notEmpty.signal();
  4. 如果出队成功,那就队列就不满,就需要通知队列不满的等待队列。就这里要用notFull.signal();

总结

java MESA模型
在这里插入图片描述
java MESA 模型中只有一个条件变量,是使用synchronized关键字来实现的。而java sdk并发包中支持多个条件变量,需要开发人员手动去调用加锁和解锁操作。

注:
借鉴极客时间java并发编程和另外一篇博客,那篇博客因电脑突然关机找不到了,如发现请通知,我在加上链接。

这篇关于临界区、管程、信号量介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1028976

相关文章

MySQL中慢SQL优化的不同方式介绍

《MySQL中慢SQL优化的不同方式介绍》慢SQL的优化,主要从两个方面考虑,SQL语句本身的优化,以及数据库设计的优化,下面小编就来给大家介绍一下有哪些方式可以优化慢SQL吧... 目录避免不必要的列分页优化索引优化JOIN 的优化排序优化UNION 优化慢 SQL 的优化,主要从两个方面考虑,SQL 语

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

Python实现html转png的完美方案介绍

《Python实现html转png的完美方案介绍》这篇文章主要为大家详细介绍了如何使用Python实现html转png功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 1.增强稳定性与错误处理建议使用三层异常捕获结构:try: with sync_playwright(

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

JAVA SE包装类和泛型详细介绍及说明方法

《JAVASE包装类和泛型详细介绍及说明方法》:本文主要介绍JAVASE包装类和泛型的相关资料,包括基本数据类型与包装类的对应关系,以及装箱和拆箱的概念,并重点讲解了自动装箱和自动拆箱的机制,文... 目录1. 包装类1.1 基本数据类型和对应的包装类1.2 装箱和拆箱1.3 自动装箱和自动拆箱2. 泛型2

四种Flutter子页面向父组件传递数据的方法介绍

《四种Flutter子页面向父组件传递数据的方法介绍》在Flutter中,如果父组件需要调用子组件的方法,可以通过常用的四种方式实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录方法 1:使用 GlobalKey 和 State 调用子组件方法方法 2:通过回调函数(Callb

Python进阶之Excel基本操作介绍

《Python进阶之Excel基本操作介绍》在现实中,很多工作都需要与数据打交道,Excel作为常用的数据处理工具,一直备受人们的青睐,本文主要为大家介绍了一些Python中Excel的基本操作,希望... 目录概述写入使用 xlwt使用 XlsxWriter读取修改概述在现实中,很多工作都需要与数据打交

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

Python实现NLP的完整流程介绍

《Python实现NLP的完整流程介绍》这篇文章主要为大家详细介绍了Python实现NLP的完整流程,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 编程安装和导入必要的库2. 文本数据准备3. 文本预处理3.1 小写化3.2 分词(Tokenizatio

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题