第18讲 什么情况下Java程序会产生死锁 如何定位、修复

it2022-05-05  105

图片右键另存为查看详细。

查看详细

什么情况下Java程序会产生死锁?如何定位、修复?

死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此一直处于等待之中,没有任何个体可以继续前进。死锁不仅仅是在线程之间会发生,存在资源独占的进程之间同样也可能出现死锁。通常来说,我们大多是聚焦在多线程场景中的死锁,指两个或多个线程之间,由于互相持有对方需要的锁,而永久处于阻塞的状态。 我们可以通过jstack或者jconsle来定位问题。

死锁产生的原因

1.竞争资源

系统中供多个进程共享的资源其数目不足以满足诸进程的需要时,会引起诸进程对资源的竞争而产生死锁。

2.进程间推进顺序非法

进程在运行过程中,请求和释放资源的顺序不当,会导致死锁。

死锁的四个必要条件

互斥条件 一段时间内某资源只由一个进程占用。如果此时还有其它进程请求该资源,则请求者只能等待,直至占有该资源的进程用毕释放。

请求和保持条件 进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

不剥夺条件 指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

环路等待条件 若干进程间形成首尾相接循环等待资源的关系。

死锁如何避免

1.尽量避免使用多个锁
2.计好锁的获取顺序
将对象(方法)和锁之间的关系,用图形化的方式表示分别抽取出来然后根据对象之间组合、调用的关系对比和组合,考虑可能调用时序按照可能时序合并,发现可能死锁的场景
3.使用带超时的方法,为程序带来更多可控性
Object.wait(…)或者CountDownLatch.await(…)指定超时时间.ReentrantLock trylock使用时候。我们希望条件允许就尝试插队,不然就按照现有公平性规则等待。一般采用如下方法: if (lock.tryLock() || lock.tryLock(timeout, unit)) { // ... }
4.静态代码分析(如FindBugs)去查找固定的模式,进而定位可能的死锁或者竞争情况

死锁检测工具

死锁demo

public class DeadLockDemo { private static String A = "A"; private static String B = "B"; public static void main(String[] args) { new DeadLockDemo().deadLock(); } private void deadLock() { Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized (A) { try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (B) { System.out.println("1"); } } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { synchronized (B) { synchronized (A) { System.out.println("2"); } } } }); t1.start(); t2.start(); } }

jstack

JDK自带的命令行工具,线程Dump分析。

Jps来查看java进程idjstack id名

JConsole

JDK自带的图形化界面工具。

JConsole使用的就是ThreadMXBean获取死锁线程并分组,然后打印相关线程信息。

具体使用 https://blog.csdn.net/abc86319253/article/details/49534225

线程进入了死循环,导致其他线程一直等待,这种问题如何诊断?

循环死锁,会导致cpu某线程的cpu时间片占用率相当高。 Linux上,可以使用top命令配合grep Java之类,找到忙的pid;然后,转换成16进制,就是jstack输出中的格式;再定位代码。 备注: jps -l 查看java进程

常见的死锁

java并发编程实战笔记:避免活跃性危险


最新回复(0)