栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

synchronized实现死锁,并使用jstack查看日志分析死锁产生原因

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

synchronized实现死锁,并使用jstack查看日志分析死锁产生原因

死锁产生的条件

简单来说,A线程持有m对象锁,想要获得n对象锁,B线程持有n对象锁,想要获得m对象锁。(因为n对象锁已经被B线程持有了,所以A线程获取不到,程序执行不下去,自己的m对象锁也无法释放,同理m对象锁也是如此)

synchronized 实现个死锁
public class MyLock2 {
    public static void main(String[] args) {
        //自己随便创建个对象.....
        Person p1 = new Person();
        Person p2 = new Person();

        new Thread(()->{
            //获取p1对象锁
            synchronized (p1) {
                System.out.println(Thread.currentThread().getName() + "-->获取到p1");
                try {
                    //不释放p1的情况下,睡眠2秒,再获取p2对象锁(意图是让另外个线程有时间先获取p2)
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (p2) {
                    System.out.println(Thread.currentThread().getName() + "-->获取到p2");
                }
            }
        },"线程1号").start();

        try {
            //睡眠0.5秒,让 线程1 先执行
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            //获取p2对象锁
            synchronized (p2) {
                System.out.println(Thread.currentThread().getName() + "-->获取到p2");
                synchronized (p1) {
                    System.out.println(Thread.currentThread().getName() + "-->获取到p1");
                }
            }
        },"线程2号").start();
    }
}

执行之后,可以看到输出,但是程序一直不结束。

线程1号-->获取到p1
线程2号-->获取到p2

此时就发生了死锁。

查看线程日志,分析死锁。
  1. windows 平台下 打开cmd 输入
tasklist | findstr java   
//类似于linux下的 grep命令

列出所有关于java的进程 , 会看到两三个关于java的进程。

输出结果类似于
java.exe    13705Console     1    53312k
java.exe    321Console       1    15382k
java.exe    13705Console     1    3253219k

一个的idea 的,一个是我们运行程序的。用他们的pid(进程id)导入日志。

如:321是我们程序的pid,导出日志。放到d盘根目录下了。

jstack -l 321 >d:321.txt

去d盘根目录下找到文件。打开。查看日志。

省略......


Found one Java-level deadlock:
=============================
"线程2号":
  waiting to lock monitor 0x00000000031ba658 (object 0x00000000d5ebb930, a com.zcc.reflect_practise.Person),
  which is held by "线程1号"
"线程1号":
  waiting to lock monitor 0x00000000031bba48 (object 0x00000000d5ebb948, a com.zcc.reflect_practise.Person),
  which is held by "线程2号"

Java stack information for the threads listed above:
===================================================
"线程2号":
	at com.zcc.thread_practise.JUC.AQS.MyLock.MyLock2.lambda$main$1(MyLock2.java:46)
	- waiting to lock <0x00000000d5ebb930> (a com.zcc.reflect_practise.Person)
	- locked <0x00000000d5ebb948> (a com.zcc.reflect_practise.Person)
	at com.zcc.thread_practise.JUC.AQS.MyLock.MyLock2$$Lambda$2/931919113.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)
"线程1号":
	at com.zcc.thread_practise.JUC.AQS.MyLock.MyLock2.lambda$main$0(MyLock2.java:29)
	- waiting to lock <0x00000000d5ebb948> (a com.zcc.reflect_practise.Person)
	- locked <0x00000000d5ebb930> (a com.zcc.reflect_practise.Person)
	at com.zcc.thread_practise.JUC.AQS.MyLock.MyLock2$$Lambda$1/1828972342.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

通过日志我们很容易看到,发现了一个死锁(Found one Java-level deadlock:)

"线程2号":
  waiting to lock monitor 0x00000000031ba658 (object 0x00000000d5ebb930, a com.zcc.reflect_practise.Person),
  which is held by "线程1号"

这一句是:(线程名称)“线程2号”等待进入monitor获取0x00000000031ba658 这个对象锁。(这个object的地址是0x00000000d5ebb930)which引导的定语从句,这个对象锁被“线程1号”持有。 同理,下一句的意思就不难得出了。所以就互相想获得对方线程持有的对象锁,但是自己的持有的对象锁又不释放。

从下面的日志从我们可以看出,发生死锁的地方,一个在代码的46行,一个在29行。

(为啥总是把锁称为对象锁呢?因为每个对象都有一把锁,这个锁保存在对象头中,对象头包含class point 和mark word 。其中class point 指向对象类型所在方法区中的Class信息。而mark word 有点复杂,简单来说,就是一块空间(包含许多东西),这个空间存放着 持有这个对象的线程local record 的地址【对象头有个空间,空间里有个地址,地址指向线程的local record】,而这个 线程 在虚拟机栈里开辟的空间,中间有一部分叫做local record,先把对象的mark word 复制到local record中,再将local record 中的owner指针,指向mark word ,就实现了对象到线程的双向绑定,所以该线程就获得了这个对象锁。汗、扯远了)

题外话:monitor 监视器。是由synchronized关键字经过编译后生成的,monitor enter 和 monitor exit ,而monitor 在操作系统层面是由mutex lock 实现的。有兴趣的可以看看 synchronized的底层实现。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/324870.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号