为了账号安全,请及时绑定邮箱和手机立即绑定

用jstack找死锁

标签:
Java

java死锁主要依靠jstack命令来查找。

检测jstack

先配置好jdk环境变量,打开一个终端命令行,输入jstack回车。如果看到如下的字样,说明jstack是可用的。

Usage:
    jstack [-l][-e] <pid>
        (to connect to running process)

Options:
    -l  long listing. Prints additional information about locks
    -e  extended listing. Prints additional information about threads
    -? -h --help -help to print this help message

死锁程序

用下面程序模拟死锁。
一个线程先拿锁1,然后拿锁2,另外一个线程先拿锁2,再拿锁1。

public class Main {

    public static final Object lock1 = new Object();
    public static final Object lock2 = new Object();
    public static void main(String[] args) {
        new Thread(
                () -> {
                    synchronized (lock1) {
                        try {
                            Thread.sleep(3000);
                            synchronized (lock2) {
                                System.out.println("thread1");
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }, "thread1").start();

        new Thread(
                () -> {
                    synchronized (lock2) {
                        try {
                            Thread.sleep(3000);
                            synchronized (lock1) {
                                System.out.println("thread2");
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }, "thread2").start();
    }
}

利用jstack检测死锁

运行好程序以后,打开终端命令行,输入

jps 

我们可以看到我们的类名Main

4080 Jps
4079 Main

前面的数字4097是进程id。
继续输入jstack pid。例子中的pid是4079.

jstack 4079

直接看最后的输出,下面的注释是为了方便解读

### java层面的死锁
Found one Java-level deadlock:
=============================
### 线程名
"thread2":
### 等待的锁,和不释放锁的线程
  waiting to lock monitor 0x00007fc2d482d8a8 (object 0x000000076ac24330, a java.lang.Object),
  ### 锁被名字叫thread1的线程获取
  which is held by "thread1"
"thread1":
  waiting to lock monitor 0x00007fc2d482b018 (object 0x000000076ac24340, a java.lang.Object),
  which is held by "thread2"

### 代码堆栈,可以定位上面的代码输出
Java stack information for the threads listed above:
===================================================
"thread2":
	at com.company.Main.lambda$main$1(Main.java:31)
	- waiting to lock <0x000000076ac24330> (a java.lang.Object)
	- locked <0x000000076ac24340> (a java.lang.Object)
	at com.company.Main$$Lambda$2/2129789493.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)
"thread1":
	at com.company.Main.lambda$main$0(Main.java:17)
	- waiting to lock <0x000000076ac24340> (a java.lang.Object)
	- locked <0x000000076ac24330> (a java.lang.Object)
	at com.company.Main$$Lambda$1/1607521710.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

### 死锁的个数
Found 1 deadlock.

根据上面的信息和堆栈,我们很快能确认死锁的代码的位置。而且可以发现锁的对象是java.lang.Object
下面是一段ReentrantLock死锁的代码,用上面的方式进行解读,找出死锁。

public class EnrtyLock {

    public static final ReentrantLock lock1 = new ReentrantLock();
    public static final ReentrantLock lock2 = new ReentrantLock();
    public static void main(String[] args) {
        // write your code here
        new Thread(
                () -> {
                    lock1.lock();
                    try {
                        Thread.sleep(3000);
                        lock2.lock();
                        System.out.println("thread1");
                        lock2.unlock();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    lock1.unlock();
                }, "thread1").start();
        new Thread(
                () -> {
                    lock2.lock();
                    try {
                        Thread.sleep(3000);
                        lock1.lock();
                        System.out.println("thread2");
                        lock1.unlock();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    lock2.unlock();
                }, "thread2").start();
    }

}


Found one Java-level deadlock:
=============================
"thread2":
  waiting for ownable synchronizer 0x000000076ac2a328, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "thread1"
"thread1":
  waiting for ownable synchronizer 0x000000076ac2a358, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "thread2"


发现锁的对象变成了ReentrantLock。证明jstack可以满足java的关键字以及基于aqs实现的锁。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
1.6万
获赞与收藏
380

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消