Java Concurrent 死锁

前言

死锁是一个比较大的概念,在并发场景下的加锁行为都有可能产生死锁问题。在Java 并发编程中会有死锁,操作系统里也有死锁,数据库里也见过死锁,分布式里也有死锁, 看上去蛮常见的,这一篇主要简单的介绍下死锁,然后说一说在并发编程中如何对待死锁。

死锁定义

死锁是指多个进程或线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将继续等待下去,此时称系统处于死锁状态或系统产生了死锁。
常见的例子:线程A现在持有A锁,线程B持有B锁,当线程A持续请求B锁不放弃,而线程B一直持有B锁不释放,并且持续请求A锁。这时候就发生了A、B线程相互等待的情况。通过这个例子,可以简单的思考一下死锁发生的几个条件,首先是互斥,拿到之后另一个不能拿,,然后是持续的请求和持续的资源的持有,再就是不会主动或被动释放(不可剥夺),形成一个简单或者复杂的环路。


image.png

产生死锁的必要条件

1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放
2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
4.循环等待条件:当发生死锁时,所等待的进程、线程必定会形成一个环路(类似于死循环),造成永久阻塞。

处理死锁一般有这样几个场景:
1、死锁的预防
2、死锁的消除
3、死锁的检测

死锁的预防策略

我觉这最好用的应该就是顺序取锁了
既然产生死锁有以上几个必要条件,那么破坏它们就好啦
1、锁超时、资源一次性分配
2、顺序取锁
3、银行家算法、鸵鸟算法等

银行家算法

有可能发生死锁就不分配,如果没有可能就分配

  1. 当一个进程对资源的最大需求量不超过系统中的资源数时可以接纳该进程。
  2. 进程可以分期请求资源,当请求的总数不能超过最大需求量。
  3. 当系统现有的资源不能满足进程尚需资源数时,对进程的请求可以推迟分配,但总能使进程在有限的时间里得到资源。
  4. 当系统现有的资源能满足进程尚需资源数时,必须测试系统现存的资源能否满足该进程尚需的最大资源数,若能满足则按当前的申请量分配资源,否则也要推迟分配。

死锁的消除

直接kill
在Java 多线程并发编程场景下,其实只要写代码时,除了数据在并发中的正确性,多少留心一下死锁,问题一般不大,毕竟没有那么多需要加锁的资源。而且使用的大多是ReentrantLock 设置时间后基本ok。

如果存在复杂的交叉取锁场景,直接顺序取锁一般问题就能解决。
这里有个观点:
因为数据是共享的,所以我们为了保证数据在并发环境下的正确性各种加锁,也就导致了死锁的产生的可能性加大,换句话说 如果不是非得共享那就线程私有,可以大幅度的解决这个问题。

你可能感兴趣的:(Java Concurrent 死锁)