前言:
眼前我们对“java互斥”大体比较注意,同学们都需要剖析一些“java互斥”的相关知识。那么小编在网络上搜集了一些对于“java互斥””的相关知识,希望咱们能喜欢,我们一起来了解一下吧!上一篇介绍操心系统中的同步互斥的基本概念,本篇继续对同步互斥进行学习
锁机制
基本概念
锁是一个更高等级的编程抽象。
包含一个二进制变量(锁定/解锁),两个操作:
Lock::Release()释放锁,唤醒任何等待的进程
Lock::Acquire()锁被释放前一直等待,然后得到锁
锁的实现
具体实现锁的时候可以实现为两种方式:
(1)有忙等待:在获取锁的时候,如果锁已经被获取了,则进程一直进行空循环,适合临界区执行时间短的情况。
(2)无忙等待。获取锁的时候,如果锁已经被获取了,则进程放到等待队列,CPU进行上下文切换,执行其他进程。适合临界区执行费时的情况。
使用Test-and-Set指令实现Acquire和Release操作:
使用Exchange指令实现进入临界区和退出临界区操作:
锁的应用
锁机制可以用于互斥问题。
信号量
信号量机制
用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便地实现了进程互斥,进程同步。
信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为1的信号量。
原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现的。软件解决方案的主要问题是由“进入区的各种操作无法一气呵成”,因此如果能把进入区,退出区的操作都用“原语”实现,使这些操作能“一气呵成”就能避免问题。
一对原语:wait(S)原语和signal(S)原语,可以把原语理解为我们自己写的函数,函数名分别为wait和signal,括号里的信号量S其实就是函数调用时传入的一个参数。wait,signal原语常简称为P,V操作。
整型信号量
用一个整数型的变量作为信号量,用来表示系统中某种资源的数量。
与普通整数变量的区别:对信号量的操作只有三种,即初始化,P操作,V操作。
我们看一个示例:
通过上述示例我们发现:“检查”和“上锁”一气呵成,避免了并发,异步导致的问题。
但是整型信号量存在的问题是:不满足“让权等待”原则,会发生“忙等”。
记录型信号量
整型信号量的缺陷是存在“忙等”问题,因此人们又提出了“记录型信号量”,即用记录型数据结构表示信号量。
wait(S)、singal(S)这对原语可记为P(S)、V(S),可用于实现系统资源的“申请”和“释放”。
S.value的初值表示系统中某种资源的数目。
对信号量S的一次P操作意味着进程请求一个单位的该类资源,因此需要执行S.value --,表示资源数减1,当S.value < 0 时表示该类资源已分配完毕,因此进程应调用block语言进行自我阻塞(当前运行的进程从运行态进入阻塞态),主动放弃处理机,并插入该类资源的等待队列S.L中。可见,该机制遵循了“让权等待”原则,不会出现“忙等”现象。
对信号量S的一次V操作意味着进程释放一个单位的该类资源,因此需要执行S.value ++,表示资源数加1,若加1后仍是S.value <= 0, 表示依然有进程在等待该类资源,因此进程应调用wakeup语言唤醒等待队列中的第一个进程(被唤醒进程从阻塞态进入就绪态)
条件变量
条件变量的概念
条件变量是管程内的等待机制
进入管程的线程因资源被占用而进入等待状态
每个条件变量表示一种等待原因,对应一个等待队列
Wait()操作
释放锁,让其他线程有机会执行,自己睡眠。
Signal()操作
唤醒等待者。
条件变量的实现
管程(monitor)
为什么会出现管程?
问题:信号量机制的不足:程序编写困难、易出错
方案:在程序设计语言中引入管程成分;一种高级同步机制
管程最早提出的时候是针对编程语言层面,不是操作系统层面。
管程的组成:
一个锁:控制管程代码的互斥访问。
0或者多个条件变量:等待/通知信号量用于管理共享数据的并发访问。
Java对管程的支持
Object类的如下方法:
void notify() :唤醒在此对象监视器上等待的单个线程。
void notifyAll() :唤醒在此对象监视器上等待的所有线程。
void wait(): 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
生产者消费者问题
(1)用信号量解决
先找出有哪些约束:
互斥约束:一次只能有一个进程操作缓冲区
同步约束:1)缓冲区为空时,消费者必须等待;2)缓冲区满时,生产者必须等待。
然后每个约束用一个单独的信号量。
互斥约束用一个二进制信号量mutex。
两个同步约束分别用两个一般信号量fullBuffers和emptyBuffers
注意:mutex的位置一定要在获取emptyBuffer和fullBuffer之后,否则会死锁。
(2)用管程(锁+条件变量)解决
总结