java线程死锁/死循环分析方法

本文介绍了如何分析Java线程的死锁和死循环问题。通过使用jps命令获取进程ID,然后利用jstack查看线程堆栈信息,识别线程间的锁竞争和长时间等待状态。在死锁分析中,展示了线程互相持有锁导致的阻塞现象。而在死循环分析部分,通过观察jstack输出的调用栈,确认程序在特定函数的某行持续运行,从而判断出现死循环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、死锁分析

1、jps命令查找所进程id:

admindeMacBook-Pro-49:~ chendu$ jps
19265 Launcher
28819 Launcher
29235 Jps
28820 Concurrent
1596 

2、jstack查看 Java 进程内当前时刻的线程快照,也就是每条线程正在执行的方法栈情况,用于定位线程停顿、死锁等长时间等待的问题。

jstack的帮助文档:

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message
admindeMacBook-Pro-49:~ chendu$  jstack -l 28820
Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007fe75300b8b8 (object 0x000000076acac7b8, a java.lang.String),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007fe75300cca8 (object 0x000000076acac7e8, a java.lang.String),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at com.sample.Concurrent$2.run(Concurrent.java:34)
        - waiting to lock <0x000000076acac7b8> (a java.lang.String)
        - locked <0x000000076acac7e8> (a java.lang.String)
        at java.lang.Thread.run(Thread.java:748)
"Thread-0":
        at com.sample.Concurrent$1.run(Concurrent.java:20)
        - waiting to lock <0x000000076acac7e8> (a java.lang.String)
        - locked <0x000000076acac7b8> (a java.lang.String)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

可以发现Thread-0的waiting to lock对象等于Thread-1的locked对象,同时Thread-1的waiting to lock对象等于Thread-0的locked对象,两个线程由于互相持有对方需要的锁而发生的阻塞现象;

例程:

package com.sample;

public class Concurrent {
    private static String resource_a = "A";
    private static String resource_b = "B";

    public static void main(String[] args) {
        deadLock();
    }

    public static void deadLock() {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource_a) {
                    System.out.println("get resource a");
                    try {
                        Thread.sleep(3000);
                        synchronized (resource_b) {
                            System.out.println("get resource b");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource_b) {
                    System.out.println("get resource b");
                    synchronized (resource_a) {
                        System.out.println("get resource a");
                    }
                }
            }
        });
        threadA.start();
        threadB.start();

    }
}

二、死循环分析

1、jps命令查找所进程id【同上】
2、jstack查看 Java 进程内当前时刻的线程快照【同上】
例程:

package com.sample;

public class Concurrent {
    @org.junit.Test
    public void test(){
        while (true);
    }
}
admindeMacBook-Pro-49:maven-sample chendu$ jstack -l 62456|grep -A 5 "main" 
"main" #1 prio=5 os_prio=31 tid=0x00007f927a804800 nid=0x2603 runnable [0x0000700005900000]
   java.lang.Thread.State: RUNNABLE
        at com.sample.Concurrent.test(Concurrent.java:6)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
--
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

多次使用jstack输出,发现在多次打出函数的调用栈时,可以发现程序一直处于RUNNABLE状态,并且一直在test函数的第6行,从而可以判断该程序处于死循环状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值