欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

死锁及其解决

程序员文章站 2022-03-08 18:58:28
...

1、死锁概述

锁在开发中会经常用到,使用起来也是非常简单。但是如果业务比较复杂,使用不当的话,会出现死锁,
这是非常严重的问题。下面代码会造成死锁。

public class DeadLock {
    private final static String A = "A";
    private final static String B = "B";

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (A){
                try{
                    Thread.sleep(1000l);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (B){
                    System.out.println("A");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (B){
                synchronized (A){
                    System.out.println("B");
                }
            }
        });

        t1.start();
        t2.start();
    }
}

在一些复杂的场景下,可能会出现上述情况。
究其原因,t1因为某些情况没有释放掉A锁,t2在获取B锁的情况下去拿A锁,此时A锁被占用拿不到,t1在释放掉A锁的情况下,去拿B锁,此时B锁又被t2占有。导致t1,t2相互占用对方待获取的锁,且又互不相让,形成死锁。

2、排查死锁问题

windows下(测试一下)
1、打开资源管理器,查看pid;或者cmd,使用jps命令。
2、使用jstack命令,dump日志
D:\Java\jdk1.8.0_211\bin>jstack 17260 > D:/mylock.txt
3、查看日志,搜索deadlock,发现如下:
死锁及其解决
4、根据实际情况解决问题

linux下:
1、使用jps找到java进程pid
2、使用jstack命令找到该进程下线程情况
jstack pid
3、找到跟我们自己代码相关的线程
定位到waiting的线程,或者deadlock的线程

一般情下,可以先找到最消耗cpu的进程,再通过jstack定位到问题代码。
1、先找到Java进程id
ps -ef | grep java
2、找出该进程内最耗费CPU的线程,可以使用top -Hp pid
top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。
3、将最费时的线程转化为16进制
printf “%x\n” 21742,得到21742的十六进制值为54ee
4、使用jstack打印堆栈信息
jstack 21711 | grep 54ee

死锁的产生条件

(1) 互斥条件:一个资源每次只能被一个进程(线程)使用。
(2) 请求与保持条件:一个进程(线程)因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件 : 此进程(线程)已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件 : 多个进程(线程)之间形成一种头尾相接的循环等待资源关系。

如何避免死锁

死锁的产生主要是因为相互占用对方想要获取的资源,导致相互等待。一般的解决方式如下:
1、·避免一个线程同时获取多个锁。
2、·避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
3、 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
4、·对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

相关标签: 并发编程