死锁是一种特定的状态,由于循环依赖导致彼此处于等待,所以出现死锁的情况,简单总结如下

图片

就是两者都持有对方需要的资源,并且不放手

死锁的常见定位就是利用jstack等工具,定位互相依赖的关系,然后找到死锁,JConsole可以再图形界面进行有限的死锁检测

我们这次就对于检测死锁的方式进行讲解

我们先看一个明显的死锁场景

public class DeadLockSample extends Thread {

private String first;

private String second;

public DeadLockSample(String name, String first, String second) {

super(name);

this.first = first;

this.second = second;

}

public  void run() {

synchronized (first) {

System.out.println(this.getName() + ” obtained: ” + first);

try {

Thread.sleep(1000L);

synchronized (second) {

System.out.println(this.getName() + ” obtained: ” + second);

}

} catch (InterruptedException e) {

// Do nothing

}

}

}

public static void main(String[] args) throws InterruptedException {

String lockA = “lockA”;

String lockB = “lockB”;

DeadLockSample t1 = new DeadLockSample(“Thread1”, lockA, lockB);

DeadLockSample t2 = new DeadLockSample(“Thread2”, lockB, lockA);

t1.start();

t2.start();

t1.join();

t2.join();

}

}

我们可以利用其看一下死锁的出现,对于死锁的检测,可以看jstack命令,或者利用JConsole图形化工具

分析得到的输出,可以看如下

图片

我们看出来上面每一个线程,都是持有了对方等待的锁

那么,其实总结是否是死锁了,就是利用查看线程的状态,对比Monitor的持有状态

而且Java内部也提供了管理API,ThreadMXBean,可以利用其对应的api去定位,去查找

代码可以如下

public static void main(String[] args) throws InterruptedException {

ThreadMXBean mbean = ManagementFactory.getThreadMXBean();

Runnable dlCheck = new Runnable() {

@Override

public void run() {

long[] threadIds = mbean.findDeadlockedThreads();

if (threadIds != null) {

ThreadInfo[] threadInfos = mbean.getThreadInfo(threadIds);

System.out.println(“Detected deadlock threads:”);

for (ThreadInfo threadInfo : threadInfos) {

System.out.println(threadInfo.getThreadName());

}

}

}

};

ScheduledExecutorService scheduler =Executors.newScheduledThreadPool(1);

// 稍等5秒,然后每10秒进行一次死锁扫描

scheduler.scheduleAtFixedRate(dlCheck, 5L, 10L, TimeUnit.SECONDS);

// 死锁样例代码…

}

这样的代码,会输出对应的死锁的输出,可以收集对应的数据,但是还是一个相对重量级的操作

那么,如何去预防对应的死锁呢?

避免 互斥

互斥也要立即释放

避免循环依赖

那么第一种方法就是尽可能的避免使用多个锁,在Java NIO中,本身模型中具有多个锁,所以可能导致死锁

第二个模式,设计好对应的锁的获取顺序,可以参考最近的银行家算法

图片

从而避免死锁

第三种,就是带有超时的获取锁

利用所谓的timed_waited 去尝试获取锁,没有获取到就直接进行退出

第四种,就是去分析死锁的可能出现场景

在类加载阶段,是可能出现死锁的,jstack等工具也不能显示全部锁信息,所以比较棘手

发表评论

邮箱地址不会被公开。 必填项已用*标注