java多线程上篇(二) -- 进程的控制、同步
一、进程的控制
进程的基本数据信息是操作系统控制管理进程的数据集合,这些信息就是用来控制进程的,此处我们说的进程控制就是进程的管理。
1. 进程的创建
2. 进程的终止
3. 进程的阻塞与唤醒
4. 进程的挂起与激活
小结
进程的控制就是操作系统对进程的主要管理工作,最重要的就是状态的切换维护。每种状态都有不同的引发事件,每种状态又有各自不同的处理步骤和过程,整个进程控制主要就是涉及这些内容。上面主要就是对这些状态进行简单的描述,以更好地对“进程的控制”这个概念有一个透彻的理解上图中的思维导图是进程控制的核心必须要理解:操作系统对于进程的控制就是对于这些状态的切换,以及切换所需要的数据维护。
二、进程的同步
(一)、进程同步概念
1.1 临界资源
一旦有对资源的共享,就必然涉及竞争限制
所以尽管A进程和B进程轮流获得时间片运行,但是当需要访问临界资源时,一旦有一个进程已经开始使用,另外的进程就不能进行使用,只能等待。
1.2 两种制约关系
既然资源访问有限制,到底有哪些场景是需要同步处理的?也就是何时会出现资源冲突?
看得出来,其实同步要解决的问题根本就是竞争,间接关系是赤裸裸的的竞争,共享同一个I/O就是一种竞争,尽管他们看似好像没有什么关系
直接的制约关系,源于进程间的合作,某种程度上来说也是一种竞争,只不过是有条件的竞争,他们共享缓冲区,当缓冲区满时只能是消费者可以运行,生产者需要阻塞,这可以认为缓冲区满这种情况下,消费者独占了缓冲区,生产者不能使用了,不过这种情况下还是说成合作比较容易理解
所以,要么是因为共享资源带来的竞争,要么就是相互合作带来的依赖。
1.3 临界区
有了临界资源的概念,就很容易理解临界区的概念,在程序中,所有的操作都是通过代码执行的,访问临界资源的那段代码就是临界区
以打水为例,所以在还没到井口,就要画一个大圈,不允许第二个人进入范围,“请站在安全黄线内”这句话熟悉么?这就是临界区。
1.4 同步规则
四种同步规则: 1. 空闲让进 2. 忙则等待 3. 有限等待 4. 让权等待
空闲让进:对于临界资源没有被使用,则谁来都可以直接使用。
忙则等待:这个就是上面的对立,如果临界资源被使用,后者就需要进行等待。
有限等待:保证在有限时间内,进入临界区,而不是一直憨憨的傻等。
让权等待:如果一直进入不了临界区,就要释放处理机,让别人进入,不能一直占着没有结果。比如超市付钱,一直连不上网,无法付钱,所以你必须让后面的人来付款,不能浪费时间和资源。
有限等待和让权等待的共同特性是必须保证有条件的退出以给其他进程提供运行的机会。简单说就是有限时间内你就要走开,你得不到更要走开,你即使能得到但是时间太久也得先让一下别人
临界区的设置就是安全黄线的设置,同步规则其实就是临界区两条黄线进出规则
对于临界区,还可以进一步细分出来进入区和退出区以及剩余区
(二)、临界区算法
Peterson算法
为了进入临界区,进程pi首先设置flag[i]为true;并且设置turn为j;显然,根据while的条件,只有flag[j] == false 或者turn == i 时,pi可以进入临界区也就是如果我想进入的话,当对方不想进入或者当前允许我进入时,我就可以进入临界区显然,如果只有一个进程想要进入,那么如上所述,对方不想进入时,可以进入临界区,符合空闲让进
(三)、同步方式之信号量
1965年,荷兰学者Dijkstra 提出的信号量(Semaphores)机制是一种卓有成效的进程同步工具。
临界区算法的原理可以让多进程对于临界区资源的访问串行化;信号量机制允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。什么是信号量?信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。-- 当它的值大于0时,表示当前可用资源的数量;-- 当它的值小于0时,其绝对值表示等待使用该资源的进程个数。
一般来说,信号量S>=0时,S表示可用资源的数量。
执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。
而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S<=0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。
一、整型信号量
最初信号量机制被称之为整型信号量
最初由Dijkstra 把整型信号量定义为一个用于表示资源数目的整型量 S,它与一般整型量不同,除初始化外,仅能通过两个标准的原子操作(Atomic Operation) wait(S)和 signal(S)来访问。
wait表示资源申请:如果S小于等于0(资源不足)等待,如果满足那么将会进行S-1,也就是申请资源
P、V操作也称之为操作原语,就是指原子操作。(原子性是指一个操作是不可中断的,要么全部执行成功要么全部执行失败)
简单来说: p操作(wait):申请一个单位资源,进程进入
PV操作的含义:PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:
②如果S<=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S): ①将信号量S的值加1,即S=S+1;
②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
使用PV操作实现进程互斥时应该注意的是:
(1)每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。
(2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。
(3)互斥信号量的初值一般为1。
优缺点
优点:效率高。
缺点: 1. 不可被中断。由于PV操作是原子操作,因此若程序在PV操作间隙出现异常进而中断PV操作,那么会造成该程序无法恢复信号量,进而导致一直锁住某块临界资源,造成程序死锁,永远无法访问。
2. 我们说,一个好的进程调度,需要满足这四个条件:闲则让进,忙则等待,有限等待,让权等待(见名词表释义),然而整型信号量无法实现让权等待,导致处理器性能降低。
二、记录型信号量
定义:一个由两部分组成的结构体。其一为整型数值(就是整型信号量),其值为正数时用于记录当前允许进入临界区的进程数量,为负数时,记录阻塞队列中进程数量;其二为链表,用于记录当前想要进入临界区的进程。
鉴于整型信号量机制中的“忙等”情况,演化出来记录型信号量,如果进程无法进入临界区,那么进入等待释放CPU资源,并且通过一个链表记录等待的进程。
semaphore {
value:int value;
L:进程等待链表(集合);
}
相对应整型信号量中的wait(S) 和 signal(S)可以描述为:
wait(S):
var S = semaphore;
S.value=S.value-1;
if S.value<0 then block(S.L); signal(S):
var S = semaphore;
S.value=S.value+1;
if S.value<=0 then wakeup(S.L);
上面的操作中,均定义了一个semaphore类型的变量S
- 如果执行 wait 操作,先执行资源减一,如果此时S.value<0,说明在申请资源之前(S.value-1),原来的资源就是<=0,那么该进程阻塞,加入等待队列L中
- 如果执行 signal 操作,先执行资源加一,如果此时S.value<=0,说明在释放资源之前(),原来的资源是<0的,那么将等待链表中的进程唤醒
- 当申请资源时,先进行S.value-1,一旦资源出现负数,说明需要等待,S.value的绝对值就是等待进程的个数,也就是S.L的长度
- 当资源恢复时,先进行S.value+1,已经有人释放资源了然而资源个数还是小于等于0,说明原来就有人在等待,所以应该去唤醒
block 和 wakeup 也都是原语,也就是原子操作。block原语,进行自我阻塞,放弃处理机,并插入到信号量链表S.L 中;wakeup原语,将S.L链表中的等待进程唤醒。
如果 S.value的初值为 1,表示只允许一个进程访问临界资源,此时的信号量转化为互斥信号量,用于进程互斥。(效果就如同Peterson算法了)
三、AND型信号量
针对于临界区算法或者是整型信号量或者是记录型信号量是针对各进程之间只共享一个临界资源而言的。
process A: process B:wait(D); wait(E);wait(E); wait(D);
process A: wait(D); 于是D=0process B: wait(E); 于是E=0process A: wait(E); 于是E=-1 A阻塞process B: wait(D); 于是D=-1 B阻塞
四、信号量集
1. Swait(S,d,d)。此时在信号量集中只有一个信号量 S,但允许它每次申请 d 个资源,当现有资源数少于d时,不予分配。
2. Swait(S,1,1)。此时的信号量集已蜕化为一般的记录型信号量(S>1时)或互斥信号量(S=1 时)。
3. Swait(S,1,0)。这是一种很特殊且很有用的信号量操作。当 S≥1 时,允许多个进程进入某特定区;当 S 变为 0 后,将阻止任何进程进入特定区。换言之,它相当于一个可控开关。
五、小结
临界区机制通过算法控制进程串行进入临界区,而信号量机制则是借助于原语操作(原子性)对临界资源进行访问控制
---- 整型信号量机制可以处理同一共享资源中,资源数目不止一个的情况---- 记录型信号量对整型信号量机制的“忙等”进行了优化,通过block以及weakup原语进行阻塞和通知---- AND型信号量机制解决了对于多个共享资源的同步---- 信号量集是对AND的再一次优化,既能够处理多个共享资源同步的问题,还能够设置资源申请的下限,是一种更加通用的处理方式
(四)、同步方式之管程
(一)、管程的定义
(二)、管程的特点
(三)、条件变量
上面可以用简单的例子解释。A在用厨房,突然临时有事,要停止做饭 离开厨房。但是他把厨房锁住,钥匙拿走,不允许排队的人做饭,必须等待他回来做完。那他什么时候回来?这个太占用资源了,所以需要找个方法解决。如下。
接着上面例子扩展理解。1. 加入A在厨房(管程)做饭,其他人在外面等着(阻塞队列),此时A来一个电话,临时有事(x的条件),需要停止做饭(阻塞),离开厨房(管程),这个时候可以让排队的人进来做(唤醒)。此时A就是阻塞状态。这个是x.wait。2. 过会A把事情处理完了回来,就让此时正在做饭的兄弟暂停(阻塞),让A开始继续做放(唤醒)。这个是x.signal个人理解,如有不符,敬请谅解!
总结
感谢 :https://www.cnblogs.com/noteless/p/10350253.html#16
java多线程上篇(二) -- 进程的控制、同步的更多相关文章
- (Java多线程系列二)线程间同步
Java多线程间同步 1.什么是线程安全 通过一个案例了解线程安全 案例:需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果. 先来看一个线程不安全的例子 class Sell ...
- Java 多线程(二)—— 线程的同步
上文创建多线程买票的例子中注释会出现错票.重票的问题,本文来讲讲如何解决此问题.本文例子:利用多线程模拟 3 个窗口卖票 实现Runnable接口 public class TestThread2 ...
- 简述Java多线程(二)
Java多线程(二) 线程优先级 Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行. 优先级高的不一定先执行,大多数情况是这样的. 优 ...
- Java多线程基础:进程和线程之由来
转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...
- “全栈2019”Java第二十二章:控制流程语句中的决策语句if-else
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- 1、Java多线程基础:进程和线程之由来
Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...
- “全栈2019”Java多线程第十六章:同步synchronized关键字详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java 多线程基础(五)线程同步
Java 多线程基础(五)线程同步 当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题. 要解决上述多线程并发访问一个资源的安全性问题,Java中提供了同步机制 ...
- Java总结篇系列:Java多线程(二)
本文承接上一篇文章<Java总结篇系列:Java多线程(一)>. 四.Java多线程的阻塞状态与线程控制 上文已经提到Java阻塞的几种具体类型.下面分别看下引起Java线程阻塞的主要方法 ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
随机推荐
- CF1174C Ehab and a Special Coloring Problem(数论)
做法 与\(x\)互质的数填不同的数,把有向关系表示出来,发现边数是不能承受的 反过来想,成倍数关系填相同的数,把这些数想象成一条链,而这条链开始的数一定是质数,\(\sum\limits_{prim ...
- 让vim更加智能化
从此,让我的vim更加的智能化,整整用了一个周日,基本是值得的: "新建.c\.cpp\.python\.sh等文件时,使用定义的函数SetTitle,自动插入文件头 func SetTit ...
- 【零基础】神经网络优化之mini-batch
一.前言 回顾一下前面讲过的两种解决过拟合的方法: 1)L0.L1.L2:在向前传播.反向传播后面加个小尾巴 2)dropout:训练时随机“删除”一部分神经元 本篇要介绍的优化方法叫mini-bat ...
- Linux信号使用及自定义信号
linux自定义信号:https://www.cnblogs.com/bigben0123/p/3186661.html linux信号.值及解释:https://blog.csdn.net/luot ...
- https://www.atlassian.com/git/tutorials/git-gc
https://www.atlassian.com/git/tutorials/git-gc The git gc command is a repository maintenance comman ...
- linux查看文件的编码格式的方法 set fileencoding
查看文件编码在Linux中查看文件编码可以通过以下几种方式:1.在Vim中 可以直接查看文件编码:set fileencoding即可显示文件编码格式.如果你只是想查看其它编码格式的文件或者想解决 用 ...
- Tomcat中配置URIEncoding="UTF-8"来处理中文的处理
Tomcat中配置URIEncoding="UTF-8"来处理中文的处理 打开 server.xml 文件,更改两个地方. 配置一:添加 URIEncoding="UTF ...
- OpenJudge计算概论-奥运奖牌计数
/*===================================================================== 奥运奖牌计数 总时间限制: 1000ms 内存限制: 6 ...
- 猎豹网校C++ Primer学习笔记2
14.数组 数组定义时的长度必须是在编译时就能确定的值. 全局数组会自动初始化为0. size_t 15.指针 其指向类型要相同. 指针和引用: 指针可以先不初始化,可以修改指向.有指针的指针. 16 ...
- 简易的CRM系统案例之SpringMVC+JSP+MySQL+myBatis框架版本
主要对上一版DAO框架的替换hibernate变成myBatis 简易的CRM系统案例之SpringMVC+JSP+MySQL+hibernate框架版本 src/mybatis.xml <?x ...