Java死锁的原因排查和解决方案
2022-01-06 11:56:08
相信程序员都会遇到这样的问题,Java死锁怎么检查呢?怎么才能解决?所以,何谓死锁?“死锁”是指两个或多个进程在执行过程中,由于相互竞争的资源或相互的通信而导致的一种阻塞现象。今日小编来帮您一次性解决Java死锁相关问题。
1.为何发生死锁?
要解决Java的死锁必须追根到底,为什么会出现死锁呢?事实上,从死锁的定义可以看出,一方面是由于过程中存在两个或多个过程,另一方面是由于存在竞争资源。
2.如何检查代码中的死锁?
(1)使用jps和jstack。
从windons命令窗口使用jps-l。
用jstack-l12316。
(2)使用jconsole。
当window打开JConsole时,JConsole是一个图形监视工具!
从windons命令窗口中输出JConsole。
选定该线程的tab。
3)使用JavaVisualVM。
打开window,jvisualvm,jvisualvm是一款图形监视工具!
从windons命令窗口,输出jvisualvm。
还是切换到这个TAB线程上,很显然有提示!
3.如何避免死锁?
前面讲了死锁出现的原因,以及通过三种方法对死锁进行检测和检查,接下来要做的事情就是如何避免死锁,如果能让编写代码避免死锁出现,那么就没有上述这些检查的过程。最好是从源头控制问题,而不要再碰到填埋场出现的问题。
以下是阿里巴巴最近发布的开发法规,其中有关于避免死锁的说明:
这是因为两个线程尝试以不同的顺序获取同一个锁。因此,如果所有的线程都是按固定顺序获得锁的,那么在程序中就没有锁顺序的死锁。
(1)动态锁定次序死锁。
通过一个典型的转帐案例,我们知道转帐意味着把钱从一个帐户转到另一个帐户。进行转移之前,必须先获取两个帐户对象得锁,以确保在不破坏某些不变形条件的情况下,以原子方式更新两个帐户中的余额,如账户余额不能为负。
总结:在transferMoney中,我们不能控制参数次序,这取决于外部输入。因此,两个线程同时调用transferMoney,一个线程从X向Y转帐,另一个线程从Y向X转移,然后会发生相互等待锁定的情况,从而导致死锁。
Authorization:定义锁的顺序,并在整个应用程序中按此顺序获得锁。
方案一:使用System.identityHashCode方法,该方法返回带有Object.hashCode返回的值,此时可以用任意一种方式确定锁的顺序。但很少情况下,两个对象可能具有相同的散列值,在这种情况下,给锁设定次序是通过对公共变量进行锁定。因此,这个方法也是以最低的成本,以最大程度的安全。
方法二:在Account中包括唯一、不可变、值。例如帐号等。用此值来对对象排序。
(2)合作对象间发生的死锁。
当锁被持有时,如果一个外部方法被调用,就会发生激活问题。其他锁定可能会在此外部方法中得到(这可能造成死锁),或者阻塞时间太长,使其他线程不能及时获取当前所持有的锁。
这个场景是这样的:Taxi表示出租车对象,包括当前地点和目标。Dispatcher代表车队。在接收到GPSupdate事件时,线程会掉用setLocation,这会首先更新计程车的位置,然后判断它是否到达了目的地。Dispatcher如果到达了,它将通知Dispatcher:需要一个新的目的地。由于setLocation和notifyAvailable都是同步方法,所以setLocation线程首先获得taxi的锁,然后再获得Dispatcher的锁。类似地,掉用getImage的线程首先获得Dispatcher的锁,然后再获得每个taxi的锁,它们以不同的顺序获得锁,因此可能会导致死锁。
对策:采用开放式互换。当另一个方法被调用时,它不需要持有锁,则该调用被称为开放掉用。该调用可以有效地避免死锁,并便于分析线程安全性。
上述是对Java死锁的查找与解决方案,希望能对您有帮助,强烈建议您在看完后一定要亲自实践一下操作过程。永远不要以为看懂就行,往往在实际操作中可以学到更多的知识。