java死锁的四个必要条件有哪些?如何进行死锁检测?

java死锁是指多个线程因竞争资源而造成的一种僵局,如果没有外力作用,这些进程都将无法向前推进。不过产生死锁是需要条件的,那java死锁的四个必要条件有哪些?下面来我们就来给大家讲解一下。

1.互斥条件:一个资源每次只能被一个进程使用。

2.占有且等待:一个进程因请求资源二阻塞时,对已获得的资源保持不放。

3.不可强行占有:进程已获得资源,在未使用完之前,不可强行剥夺。

4.循环等待条件:若干进程之前行程一种头尾相接的循环等待资源关系。

如何进行死锁检测?

每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。例如,线程A请求锁7,但是锁7这个时候被线程B持有,这时线程A就可以检查一下线程B是否已经请求了线程A当前所持有的锁。如果线程B确实有这样的请求,那么就是发生了死锁(线程A拥有锁1,请求锁7;线程B拥有锁7,请求锁1)。

当然,死锁一般要比两个线程互相持有对方的锁这种情况要复杂的多。线程A等待线程B,线程B等待线程C,线程C等待线程D,线程D又在等待线程A。线程A为了检测死锁,它需要递进地检测所有被B请求的锁。从线程B所请求的锁开始,线程A找到了线程C,然后又找到了线程D,发现线程D请求的锁被线程A自己持有着。这是它就知道发生了死锁。

下面是一幅关于四个线程(A,B,C和D)之间锁占有和请求的关系图。像这样的数据结构就可以被用来检测死锁。

java死锁的四个必要条件有哪些?如何进行死锁检测?.jpg

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

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

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

死锁检测可以更好的预防死锁,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。最后大家如果想要了解更多java常见问答知识,敬请关注奇Q工具网。

推荐阅读:

json对象和java对象的区别是什么?两者如何相互转换?

sql语句如何删除表中一行数据?sql有哪些常用语句?

java编程是如何应用到芯片上的?java编程应用原理