美文网首页
死锁与问题排查

死锁与问题排查

作者: ________方块丶 | 来源:发表于2021-01-01 11:17 被阅读0次

本篇文章从Java线程、锁层面去考虑考虑死锁。

死锁:多个线程,彼此持有对方需要的锁资源,谁也不肯释放,谁也无法进行,而导致的僵死局面。比如:T1持有L1锁,需要L2锁才能运行,T2持有L2锁,需要L1锁才能够运行。

活锁:多个线程,彼此谦让对方需要的锁资源,谁也不能够拥有所资源,谁也没法进行的尴尬局面。比如:T1持有L1锁,发现没法获取到L2锁,立马释放L1,T2持有L2锁,发现没法获取L1锁,立马释放L2锁,如此反复。

死锁产生的四个条件

死锁产生需要依赖下面四个条件,缺一不可

  1. 互斥:共享资源只能被一个线程占用,如T1,T2
  2. 占有且保持:线程T1已占有L1锁资源,再去请求L2锁资源时,并不会释放L1资源。
  3. 不可抢占:其他线程不能争夺T1已经占用的资源。
  4. 循环等待:T1等待T2释放L2,T2等待T1释放L1

简单死锁示例

/**
 * 死锁例子
 * 线程L1 持有L1的情况下,尝试获取L2
 * 线程L2 持有L2的情况下,尝试获取L1
 */
public class DeadLockDemo {
    public static void main(String[] args) {
        Object L1 = new Object();
        Object L2 = new Object();
        Thread T1 = new Thread(() -> {
            while (true) {
                synchronized (L1) {
                    synchronized (L2) {
                        //do something
                    }
                }
            }

        });
        Thread T2 = new Thread(() -> {
            while (true) {
                synchronized (L2) {
                    synchronized (L1) {
                        //do something
                    }
                }
            }
        });
        T1.start();
        T2.start();
    }
}

以上变量明明不值得参考

死锁排查

线程相关的排查比较简单,一般使用jpsjstack命令就可以搞定。

// 首先获取相关JVM的进程编号,可以看到目标JVM进程为6625
jps -l

6624 org.jetbrains.jps.cmdline.Launcher
6625 DeadLockDemo
6626 sun.tools.jps.Jps
4307 org.jetbrains.idea.maven.server.RemoteMavenServer36
382 
// 利用jstack JVM进程号打印线程栈信息,可以看到连个相互等待
jstack 6625


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f8f8a00eeb8 (object 0x000000076ac33cd8, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f8f8a0104b8 (object 0x000000076ac33ce8, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at DeadLockDemo.lambda$main$1(DeadLockDemo.java:26)
        - waiting to lock <0x000000076ac33cd8> (a java.lang.Object)
        - locked <0x000000076ac33ce8> (a java.lang.Object)
        at DeadLockDemo$$Lambda$2/668386784.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
"Thread-0":
        at DeadLockDemo.lambda$main$0(DeadLockDemo.java:16)
        - waiting to lock <0x000000076ac33ce8> (a java.lang.Object)
        - locked <0x000000076ac33cd8> (a java.lang.Object)
        at DeadLockDemo$$Lambda$1/381259350.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

其他工具如JConsole也可以达到排查的效果,这里建议,大家在开发的过程中把线程重新起个名字,方便排查问题。

如何避免死锁

死锁产生需要四个条件同时满足,破坏任何一个条件,就可以避免死锁产生。第一个条件是在并发条件下,访问临界区域下必须的,因此不做考虑。

  • 破坏占有且等待:一次性获取所有的锁资源。例如,上面的例子,可以用一个L1_2锁来代表L1,L2。只用锁一次
  • 破坏不可抢占:当T1持有L1锁,但获取不到L2锁的时候,可以放弃L1锁。即尝试获取L2锁,超过时间没有获取到则T1放弃已占用的L1锁。但原生的synchronized的方式并不支持,需要用到JUC中的Lock,尝试获取锁。一般尝试获得锁需要增加尝试时间,尝试时间需要做随机处理。否则可能发生,T1让了L1的同时T2让了L2,相互让锁,产生活锁现象。
  • 破坏循环等待:让每个T1,T2获取锁的顺序保持一直,就可以避免相互之间的等待。

这里不得不提一下“银行家算法”,也是解决共享资源分配避免死锁的一种方案。推荐一篇博客,https://blog.csdn.net/qq_36260974/article/details/84404369 供大家参考。

相关文章

  • 死锁与问题排查

    本篇文章从Java线程、锁层面去考虑考虑死锁。 死锁:多个线程,彼此持有对方需要的锁资源,谁也不肯释放,谁也无法进...

  • 《作死故障篇三》- 如何快速定位死循环

    项目发布后,发现机器的cpu飙升,load升高。在排查问题的过程中首先想到的应该是排查一下死锁、死循环。死锁与死循...

  • 死锁问题排查

    首先使用jps查询进程ID然后使用jstack和进程ID查询堆栈日志信息。

  • 死锁问题排查

    最近在处理现场问题中偶然发现从日志中发现事务间死锁,与以往认知不大相符,故而进行记录。1.死锁死锁一般指的是两个事...

  • jstack命令:教你如何排查多线程问题

    这是之前的一个死锁案例: 一个多线程死锁案例,如何避免及解决死锁问题? 如程序中发生这样的死锁问题该如何排查呢?我...

  • java死锁问题排查

    首先熟悉一下jstack命令的用法,主要参数有-F -l -m 如下图: 模拟一段死锁的java代码,如下: ``...

  • MySQL死锁问题排查

    概述 在开发中经常用到的mysql数据库,mysql作为开源的数据库有很多优越的地方;大家可以不了解其中的原理,但...

  • 2020-04-08数据库死锁问题排查

    在测试同学测试过程中偶然发现日志中出现异常死锁日志如下: 出现问题后,立刻定位日志,排查死锁原因。以下为排查过程,...

  • Mysql死锁如何排查:insert on duplicate死

    前言 遇到Mysql死锁问题,我们应该怎么排查分析呢?之前线上出现一个insert on duplicate死锁问...

  • Java相关的性能调优方案

    本文介绍了在性能测试过程中Java进程消耗CPU过高的问题排查方法、线程死锁问题排查方法和内存泄露的排查方法 Ja...

网友评论

      本文标题:死锁与问题排查

      本文链接:https://www.haomeiwen.com/subject/wfqjoktx.html