多线程死锁的产生原因以及如何避免

多线程以改善了系统资源的利用率并且提高了系统的处理能力。但是,并发执行同时也带来了新的问题——死锁。所谓的死锁就是多个线程因竞争资源而造成的一种互相等待,如果没有外力作用,这些线程都将无法继续执行

死锁产生的原因

系统资源的竞争

通常系统中拥有的不可剥夺资源,其数量不足以满足多个线程运行的需要,使得线程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。

线程推进顺序非法

线程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发线程 P1、P2分别保持了资源R1、R2,而线程P1申请资源R2,线程P2申请资源R1时,两者都 会因为所需资源被占用而阻塞。

信号量使用不当也会造成死锁。线程间彼此相互等待对方发来的消息,结果也会使得这 些线程间无法继续向前推进。例如,线程A等待线程B发的消息,线程B又在等待线程A 发的消息,可以看出线程A和B不是因为竞争同一资源,而是在等待对方的资源导致死锁。

死锁产生的必要条件

产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。

  1. 互斥条件:线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个线程所占有。此时若有其他线程请求该资源,则请求线程只能等待
  2. 不剥夺条件:线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能 由获得该资源的线程自己来释放(只能是主动释放)
  3. 请求和保持条件:线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他线程占有,此时请求线程被阻塞,但对自己已获得的资源保持不放
  4. 循环等待条件:存在一种线程资源的循环等待链,链中每一个线程已获得的资源同时被 链中下一个线程所请求。即存在一个处于等待状态的线程集合{Pl, P2, ..., pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有

如何避免

在有些情况下死锁是可以避免的。三种用于避免死锁的技术:

  1. 加锁顺序
  2. 加锁时限
  3. 死锁检测

加锁顺序

当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就容易发生。

按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要事先知道所有可能会用到的锁,但总有些时候是无法预知的。

加锁时限

当一个线程在尝试获取锁的过程中超过了这个时限则该线程应该放弃对该锁进行请求。

若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行。

需要注意的是,由于存在锁的超时,所以我们不能认为这种场景就一定是出现了死锁。也可能是因为获得了锁的线程(导致其它线程超时)需要很长的时间去完成它的任务。

此外,如果有非常多的线程同一时间去竞争同一批资源,就算有超时和回退机制,还是可能会导致这些线程重复地尝试但却始终得不到锁。如果只有两个线程,并且重试的超时时间设定为0到500毫秒之间,这种现象可能不会发生,但是如果是10个或20个线程情况就不同了。因为这些线程等待相等的重试时间的概率就高的多(或者非常接近以至于会出现问题)。

死锁检测

死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。

每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。

当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。

那么当检测出死锁时,这些线程该做些什么呢?

一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁(编者注:原因同超时类似,不能从根本上减轻竞争)。

一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。

原文地址:https://www.cnblogs.com/AmosH/p/10346923.html

时间: 2024-10-09 21:32:28

多线程死锁的产生原因以及如何避免的相关文章

java 多线程死锁问题

什么是死锁 所谓死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去. 死锁产生的原因及条件 那么为什么会产生死锁呢? 1.因为系统资源不足. 2.进程运行推进的顺序不合适. 3.资源分配不当. 学过操作系统的朋友都知道:产生死锁的条件有四个: 1.互斥条件:所谓互斥就是进程在某一时间内独占资源. 2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放. 3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺

多线程死锁的产生以及如何避免死锁

一.死锁的定义 多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力.然而,并发执行也带来了新的问题--死锁.所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进. 下面我们通过一些实例来说明死锁现象. 先看生活中的一个实例,2个人一起吃饭但是只有一双筷子,2人轮流吃(同时拥有2只筷子才能吃).某一个时候,一个拿了左筷子,一人拿了右筷子,2个人都同时占用一个资源,等待另一个资源,这个时候甲在等待乙吃完并释放它占有的筷子,同理,乙也在等待甲吃

Java多线程死锁避免方法

一.什么是死锁当两个或两个以上的线程在执行过程中,因为争夺资源而造成的一种相互等待的状态,由于存在一种环路的锁依赖关系而永远地等待下去,如果没有外部干涉,他们将永远等待下去,此时的这个状态称之为死锁.经典的 "哲学家进餐" 问题很好地描述了死锁状况:5个哲学家去吃中餐,坐在一张圆桌旁,他们有5根筷子(而不是5双),并且每两个人中间放一根筷子,哲学家们要么在思考,要么在进餐,每个人都需要一双筷子才能吃到东西,并在吃完后将筷子放回原处继续思考,有些筷子管理算法 (1) 能够使每个人都能相对

死锁产生的原因、必要条件和场景解析·

死锁是是进程死锁的简称,指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进.它是计算机操作系统乃至并发程序设计中最难处理的问题之一. 举个简单的例子,系统中只有一台CD-ROM驱动器和一台打印机,某一个进程占有了CD-ROM驱动器,又申请打印机:另一进程占有了打印机,还申请CD-ROM.结果,两个进程都被阻塞,永远也不能自行解除.这就是死锁. 产生死锁的主要原因有三点: (一)系统资源不足: (二)进程运行推进的顺序不对: (三)系统

Oracle常见死锁发生的原因以及解决方法

Oracle常见死锁发生的原因以及解决办法 一,删除和更新之间引起的死锁 造成死锁的原因就是多个线程或进程对同一个资源的争抢或相互依赖.这里列举一个对同一个资源的争抢造成死锁的实例. Oracle 10g, PL/SQL version 9.2 CREATE TABLE testLock(  ID NUMBER, test VARCHAR(100)  ) COMMIT INSERT INTO testLock VALUES(1,'test1'); INSERT INTO testLock VAL

Oracle死锁产生的原因和解决办法

如果有两个会话,每个会话都持有另一个会话想要的资源,此时就会发生死锁.用下面实验来说明死锁的产生原因和解决办法.SESSION1:SQL> create table t2 as select * from emp;SQL> select * from t2 where empno=7369; EMPNO ENAME      JOB              MGR HIREDATE                 SAL       COMM     DEPTNO---------- ---

死锁产生的原因&&必要条件&&如何避免死锁

产生死锁的原因主要是:(1) 因为系统资源不足.(2) 进程运行推进的顺序不合适.(3) 资源分配不当等.如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁.其次,进程运行推进顺序与速度不同,也可能产生死锁. 产生死锁的四个必要条件:死锁的4个必要条件:(1)互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用.(2)请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源.(3)非剥

死锁产生的原因和条件简述

深入理解死锁产生的原因和条件,对于日后避免死锁的产生有着非常重要的意义.死锁产生的原因主要是竞争资源,其产生的条件包括资源互斥.请求保持.不能剥夺和循环等待. 死锁产生的根本原因是资源竞争.如果若干个线程正常运行,遇到彼此需要对方占有的资源时,就可能产生线程死锁.如果若干个线程异常运行,资源的请求与释放的顺序不当,也可能产生死锁. 死锁产生的条件包括以下4点: 资源互斥:即资源仅能让一个线程使用而不支持多个线程同时使用. 请求保持:已经拥有资源的线程在请求其他资源时并没有释放当前资源. 不能剥夺

多线程学习笔记三--------------多线程死锁

多线程死锁: 死锁的常见情形之一:同步的嵌套. public class DeadLock { public static void main(String[] args) throws InterruptedException { Customer cus = new Customer(); Thread t1 = new Thread(cus); Thread t2 = new Thread(cus); t1.start(); Thread.sleep(5); cus.flag = fals