您的位置:首页 > 其它

什么是线程锁和进程锁?什么是死锁,死锁产生的原因和解决锁的办法

2019-03-18 08:07 274 查看

  1. 线程锁:当多个线程几乎同时修改一个共享数据的时候,需要进行同步控制,线程同步能够保证多个线程安全的访问竞争资源(全局内容),最简单的同步机制就是使用互斥锁。

    某个线程要更改共享数据时,先将其锁定,此时资源的状态为锁定状态,其他线程就能更改,直到该线程将资源状态改为非锁定状态,也就是释放资源,其他的线程才能再次锁定资源。互斥锁保证了每一次只有一个线程进入写入操作。从而保证了多线程下数据的安全性。

  2. 进程锁:也是为了控制同一操作系统中多个进程访问一个共享资源,只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,但是可以使用本地系统的信号量控制。

  3. 死锁:在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。

    当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。

当然死锁的产生是必须要满足一些特定条件的:

  1. 互斥条件:进程对于所分配到的资源具有排它性,即资源不能被共享,只能由一个进程使用(一个资源只能被一个进程占用,直到被该进程释放 。)

  2. 请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。

  3. 非剥夺条件:任何一个资源在没被该进程释放之前,任何其进程都无法对他剥夺占用。

  4. 循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。

  5. 递归死锁:在多线程的环境下使用递归,遇到了多线程那么就不得不面对同步的问题。而递归程序遇到同步的时候很容易出问题。

    多线程的递归就是指递归链中的某个方法由另外一个线程来操作。

解决死锁的办法有:

  1. 按同一顺序访问对象。(注:避免出现循环)

  2. 避免事务中的用户交互。(注:减少持有资源的时间,较少锁竞争)

  3. 保持事务简短并处于一个批处理中。(注:同(2),减少持有资源的时间)

  4. 使用较低的隔离级别。(注:使用较低的隔离级别(例如已提交读)比使用较高的隔离级别(例如可序列化)持有共享锁的时间更短,减少锁竞争)

  5. 尽量减少资源占用的时间,可以降低死锁的发生的概率

  6. 银行家算法。

    要想说银行家,首先得说死锁问题,因为银行家算法就是为了死锁避免提出的。那么,什么是死锁?简单的举个例子:俩人吃饺子,一个人手里拿着酱油,一个人手里拿着醋,拿酱油的对拿着醋的人说:“你把醋给我,我就把酱油给你”;拿醋的对拿着酱油的人说:“不,你把酱油给我,我把醋给你。”

    于是,俩人这两份调料是永远吃不上了。这就是死锁。

    那么,为啥这个算法叫银行家算法?因为这个算法同样可以用于银行的贷款业务。让我们考虑下面的情况。

    一个银行家共有20亿财产
    第一个开发商:已贷款15亿,资金紧张还需3亿。
    第二个开发商:已贷款5亿,运转良好能收回。
    第三个开发商:欲贷款18亿

    在这种情况下,如果你是银行家,你怎么处理这种情况?一个常规的想法就是先等着第二个开发商把钱收回来,然后手里有了5个亿,再把3个亿贷款给第一个开发商,等第一个开发商收回来18个亿,然后再把钱贷款给第三个开发商。
    这里面什么值得学习呢?最重要的就是眼光放长一点,不要只看着手里有多少钱,同时要注意到别人欠自己的钱怎么能收回来。

    那么正经点说这个问题,第一个例子中:醋和酱油是资源,这俩吃饺子的是进程;第二个例子中:银行家是资源,开发商是进程。在操作系统中,有内存,硬盘等等资源被众多进程渴求着,那么这些资源怎么分配给他们才能避免“银行家破产”的风险?

    银行家算法----安全序列

    安全序列是指对当前申请资源的进程排出一个序列,保证按照这个序列分配资源完成进程,不会发生“酱油和醋”的尴尬问题。

Available = []  #各可用资源数目
Used ={}        #某进程目前占有各资源数
Need = {}       #某进程目前需求资源数
zhan = []       #临时存储列表
order = []      #进程安全顺序列表
pandaun = []
def compare(a = [],b = []):
for x in range(0,item): #进行列表对应元素的比较
if (int(a[x]) < int(b[x])): #一旦出现供不应求的情况即返回False
return False
break           #且跳出循环
return True             #如果符合条件即返回True
def AddUsed(a = [],b = []): #可用资源某进程当前占用资源对应位置相加
for x in range(0,item):
a[x] = int(a[x]) + int(b[x])
item = int(input("请输入资源种类数: "))
SP = int(input("请输入进程数: "))
jinchengshu = SP            #设置临时变量表示进程数量,在后面的判断中用
#输入各类资源的可用数目并存储到列表Available中
for x in range(1,item+1):
Available.append(input("请输入第"+str(x)+"种资源的可用数目: "))
#输入各进程名称,占有资源数及所需,键值对存储
for x in range(1,SP+1):
name = input("请输入第"+str(x)+"个进程名称: ")
print("该进程占有的"+str(item)+"类资源数为:")
for y in range(1,item+1):
zhan.append(int(input()))
Used[name] = zhan
zhan = []   #清空临时列表
print("该进程需要的"+str(item)+"类资源数为:")
for z in range(1,item+1):
zhan.append(int(input()))
Need[name] = zhan
zhan = []   #清空临时列表
#安全性算法开始
while Need:                     #如果进程表Need不为空
for key in Need:            #获取Need中的key
zhan = Need[key]        #将对应的value赋值给临时列表zhan
if compare(Available,zhan):#调用比较函数比较列表中个元素与Avilable中个元素的大小并返回真值
AddUsed(Available,Used[key]) #如果返回True则调用相加函数
order.append(key)   #将key值放入order列表中以便显示
a = key             #设置a令它等于key,删除字典元素时使用
break
if compare(Available,zhan): #如果符合大小条件就删除对应的键值对
del Need[a]
jinchengshu -= 1
if SP == jinchengshu:
print("不存在安全序列!!!")
break
if jinchengshu == 0:
for x in range(0,len(order)):
print(order[x]+'-->',end='')
print("END!")
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: