java 并发 数据库死锁
如何在编写并发程序时避免死锁 -Java示例
Java中的多线程和并行计算
大家好,您是否想学习在编写并发程序时如何避免死锁,尤其是在Java中? 编写正确的并发应用程序绝非易事,因为您必须处理一些并发问题,例如竞态条件 ,活动锁, 死锁 ,内存干扰等。
在本文中,我将告诉您如何在编写并发程序作为面试问题讨论时避免死锁。 由于我是Java开发人员,因此我将解释Java的概念和实现,但是我将与您共享的技术适用于所有编程语言,例如C ++或C#等。
避免死锁的问题是流行的Java面试问题之一 ,多线程处理主要是在高层面试中提出的,其中涉及许多后续问题。
尽管这个问题看起来很基本,但是一旦您开始深入研究,大多数Java开发人员就会陷入困境。
那么, 什么是僵局? 答案很简单-当两个或多个线程彼此等待释放所需的资源(锁定)并无限期陷入困境时,这种情况称为死锁。
它只会在多任务 或多线程的情况下发生,因为这是多线程进入的地方。
1.如何在Java中检测死锁?
尽管这可能会有很多答案,但首先,我将查看代码以查看嵌套的同步块是否正在从另一个调用同步方法 ,或者它是否试图锁定另一个对象。
如果是这种情况,如果开发人员不小心,则很有可能发生死锁。
确定死锁风险的另一种方法是在运行应用程序时实际上陷入僵局。
如果发生这种情况,请尝试进行线程转储 ,在Linux中,您可以通过命令“ kill -3”来执行此操作。 这将在应用程序日志文件中打印所有线程的状态,您可以看到哪个线程锁定在哪个对象上。
您可以使用fastthread.io之类的工具来分析该线程转储,该工具允许您上载线程转储并进行分析。
另一种方法是使用jConsole / VisualVM 。 它将准确显示锁定的线程和对象。
如果您对学习故障排除工具和分析线程转储的过程感兴趣,建议您看一下Uriah Levy在Pluralsight上的“ 分析Java线程转储”课程。
这是一门高级实践课程,旨在学习有关Java线程转储的更多信息,并使您熟悉其他流行的高级故障排除工具。
分析Java线程转储
顺便说一句,您需要具有Pluralsight会员身份才能访问此课程,该课程每月费用约为$ 29或每年$ 299 (折扣14%)。
如果您没有Pluralsight会员资格 ,我鼓励您获得一个,因为它可以让您访问他们的5000多个在线课程,这些课程涉及前端和后端开发,机器学习等所有最新主题。
它还包括交互式测验,练习和最新的认证材料。 它更像是面向软件开发人员的Netflix,并且由于学习是我们工作的重要组成部分,因此Plurlasight会员资格是保持竞争优势的绝佳方法。
他们还提供了10天的免费试用,没有任何承诺,这是一种绝佳的方式,不仅可以免费访问此课程,而且可以在加入Pluralsight之前检查课程的质量。
2.编写将导致死锁的Java程序
一旦回答了前面的问题,他们可能会问您如何编写代码,从而导致Java陷入僵局。
这是一种实现方法:
Java中的多线程和并行计算
如果method1()和method2()都被两个或多个线程调用,则很有可能发生死锁 ,因为如果线程1在执行method1()时获取了String对象的锁,而线程2则获取了Integer的锁,在执行method2()的对象时, 两者都将彼此等待以释放对Integer 的锁定 ,并且String继续进行下去,这将永远无法进行。
此图有效地演示了我们的程序,其中一个线程在一个对象上持有一个锁,并在等待另一对象持有的另一对象被锁定。
将并发和多线程应用于常见的Java模式
您可以看到线程1想要锁定对象2,该对象由线程2持有,线程2想要锁定对象1,该对象1由线程1持有。
由于没有线程愿意放弃,因此存在死锁,并且Java程序被卡住了。 这种情况也称为“没有抢占的循环等待”。
这个想法是,您应该知道使用公共并发模式的正确方法,如果您不熟悉它们,那么Jose Paumard的《 将并发和多线程应用于公共Java模式》是学习的一个很好的起点。
3.如何避免Java中的死锁
现在,面试官进入最后一部分,这是我认为最重要的问题之一: 如何解决代码的僵局?
如果您仔细查看了上面的代码,那么您可能已经发现造成死锁的真正原因不是多个线程,而是它们请求锁定的方式。
如果您提供 有序访问权限 ,则问题将得到解决。
这是我的固定版本,它通过使用没有抢占的循环等待来避免死锁。 这是死锁所需的四个条件之一
Heinz Kabutz的Java Concurrency in Practice Bundle
现在,将不再有死锁,因为这两个方法都以相同的顺序访问Integer和String类文字的锁。
因此,如果线程A获得了对Integer对象的锁定,则直到线程A释放Integer锁定后,线程B才会继续进行。
即使线程B持有String锁,也以不会阻塞线程A的相同方式完成此操作,因为现在,线程B将不希望线程A释放整数锁来继续进行任何操作。
这就是如何在编写并发程序时避免死锁 。 正如我已经说过的,即使是Java的讨论和示例,我共享的技术,对共享资源的有序访问也是独立于语言的,并且适用于所有地方。
正式地,这被称为打破死锁所需的无等待的循环等待条件,但我只是称其为共享资源的有序访问。
结束语
感谢您到目前为止阅读本文。 您可能会认为这很琐碎,但是我告诉您,这是一个重要的概念,对于编写正确的并发程序以及在面试中表现出色都很重要。
归根结底,您应该对这里提到的事情有足够的知识和经验。
并发编程之旅祝您好运! 当然这并非易事 ,但是通过遵循此路线图和指南,您距离成为更好的开发人员仅一步之遥 ,而您一直想成为