如何避免Java死锁? 是Java面试中最受欢迎的问题之一,也是本季多线程的风格,主要是在高层提出,并带有很多后续问题。 尽管问题看起来很基础,但是一旦您开始深入研究,大多数Java开发人员就会陷入困境。
面试问题始于“什么是僵局?”
当两个或多个线程正在等待彼此释放所需的资源(锁定)并无限期陷入困境时,答案很简单,这种情况称为死锁。 它只会在多任务 或多线程的情况下发生。
如何检测Java中的死锁?
尽管这可能会有很多答案,但我的版本是:如果我看到一个嵌套的同步块或从另一个调用一个同步方法,或者试图锁定另一个对象,那么我将看一下代码,那么很有可能发生死锁如果开发人员不是很谨慎。
另一种方法是在运行应用程序时实际上陷入僵局时找到它,尝试进行线程转储,在Linux中,您可以通过“ kill -3”命令执行此操作,这将在应用程序日志文件中打印所有线程的状态您可以看到哪个线程锁定在哪个对象上。
您可以使用fastthread.io之类的工具来分析该线程转储,该工具允许您上载线程转储并进行分析。
另一种方法是使用jConsole / VisualVM ,它将确切显示正在锁定的线程以及在哪个对象上。
编写Java程序会导致死锁?
一旦回答了前面的问题,他们可能会要求您编写代码,这会导致Java死锁?
这是我的版本之一:
/*** Java program to create a deadlock by imposing circular wait.* * @author WINDOWS 8**/
public class DeadLockDemo {/** This method request two locks, first String and then Integer*/public void method1() {synchronized (String.class) {System.out.println("Aquired lock on String.class object");synchronized (Integer.class) {System.out.println("Aquired lock on Integer.class object");}}}/** This method also requests same two lock but in exactly* Opposite order i.e. first Integer and then String. * This creates potential deadlock, if one thread holds String lock* and other holds Integer lock and they wait for each other, forever.*/public void method2() {synchronized (Integer.class) {System.out.println("Aquired lock on Integer.class object");synchronized (String.class) {System.out.println("Aquired lock on String.class object");}}}
}
如果method1()和method2()都将被两个或多个线程调用,则死锁的可能性很大,因为如果线程1在执行method1()时获得Sting对象的锁,而线程2在执行method2时获得Integer对象的锁, () 都将互相等待,以释放对Integer的锁定 ,而String继续进行下去,这将永远不会发生。
此图准确地演示了我们的程序,其中一个线程在一个对象上持有一个锁,然后等待另一线程持有的其他对象锁。
您会看到线程1想要锁定对象2的锁,该对象2由线程2持有,而线程2想要锁定对象1的锁,该对象1由线程1持有。由于没有线程愿意放弃,因此存在死锁,并且线程2 Java程序被卡住。
如何避免Java死锁?
现在,面试官进入最后一部分,在我看来,这是最重要的部分。
您如何解决代码中的死锁? 或如何避免Java中的死锁?
如果您仔细查看了上面的代码,那么您可能已经发现造成死锁的真正原因不是多个线程,而是它们请求锁定的方式,如果您提供有序访问,那么问题将得到解决。
这是我的固定版本,它通过无效循环的循环等待来避免死锁, 而没有抢占 ,这是需要死锁的四个条件之一。
public class DeadLockFixed {/*** Both method are now requesting lock in same order, first Integer and then String.* You could have also done reverse e.g. first String and then Integer,* both will solve the problem, as long as both method are requesting lock* in consistent order.*/public void method1() {synchronized (Integer.class) {System.out.println("Aquired lock on Integer.class object");synchronized (String.class) {System.out.println("Aquired lock on String.class object");}}}public void method2() {synchronized (Integer.class) {System.out.println("Aquired lock on Integer.class object");synchronized (String.class) {System.out.println("Aquired lock on String.class object");}}}
}
现在将没有任何死锁,因为这两个方法都以相同的顺序访问Integer和String类文字的锁。 因此,如果线程A获得了对Integer对象的锁定,则线程B直到线程A释放Integer锁定后才会继续进行,即使线程B持有字符串锁,线程A也不会被阻塞,因为现在线程B不会期望线程A释放整数锁可继续进行。
感谢您阅读本文。 如果您喜欢这篇文章,请与您的朋友和同事分享。 如果您有任何疑问或反馈,请留言。
翻译自: https://www.javacodegeeks.com/2018/08/avoid-deadlock-java-threads.html