Skip to content

JCA分析线程快照

  • JCA是IBM提供的一个线程快照的图形化分析工具

下载链接: https://www.ibm.com/support/pages/ibm-thread-and-monitor-dump-analyzer-java-tmda

  • jstack -l <PID>生成线程快照, -l表示除堆栈外, 显示关于锁的附加信息
  • 生成线程快照的目的主要在于定位线程出现长时间停顿(死锁, 死循环, 慢线程等)或CPU使用率高的原因

线程状态

1745408551436

  • new, 新建
  • runnable, 运行中, 可能持有锁(blocked)
  • blocked, 阻塞并等待监视器锁
  • waiting, 无限期等待
  • timed_waiting, 计时等待
  • terminated, 结束

分析线程死锁案例

死锁示例代码

java
public class DeadLockDemo {
    private static Object resource1 = new Object();//资源 1
    private static Object resource2 = new Object();//资源 2

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (resource1) {
                System.out.println(Thread.currentThread() + "get resource1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource2");
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2");
                }
            }
        }, "线程 1").start();

        new Thread(() -> {
            synchronized (resource2) {
                System.out.println(Thread.currentThread() + "get resource2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource1");
                synchronized (resource1) {
                    System.out.println(Thread.currentThread() + "get resource1");
                }
            }
        }, "线程 2").start();
    }
}


------------------
C:\Java\jdk1.8.0_351\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:4226,suspend=y,server=n -javaagent:C:\Users\xinzhang0618\AppData\Local\JetBrains\IntelliJIdea2022.2\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "C:\Java\jdk1.8.0_351\jre\lib\charsets.jar;C:\Java\jdk1.8.0_351\jre\lib\deploy.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\access-bridge-64.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\cldrdata.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\dnsns.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\jaccess.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\jfxrt.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\localedata.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\nashorn.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\sunec.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\sunjce_provider.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\sunmscapi.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\sunpkcs11.jar;C:\Java\jdk1.8.0_351\jre\lib\ext\zipfs.jar;C:\Java\jdk1.8.0_351\jre\lib\javaws.jar;C:\Java\jdk1.8.0_351\jre\lib\jce.jar;C:\Java\jdk1.8.0_351\jre\lib\jfr.jar;C:\Java\jdk1.8.0_351\jre\lib\jfxswt.jar;C:\Java\jdk1.8.0_351\jre\lib\jsse.jar;C:\Java\jdk1.8.0_351\jre\lib\management-agent.jar;C:\Java\jdk1.8.0_351\jre\lib\plugin.jar;C:\Java\jdk1.8.0_351\jre\lib\resources.jar;C:\Java\jdk1.8.0_351\jre\lib\rt.jar;C:\xz\code\pa-ai-common\demo\demo-springboot\target\classes;C:\xzRepository\org\springframework\retry\spring-retry\1.2.5.RELEASE\spring-retry-1.2.5.RELEASE.jar;C:\xzRepository\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-aspects\5.2.3.RELEASE\spring-aspects-5.2.3.RELEASE.jar;C:\xzRepository\org\aspectj\aspectjweaver\1.9.5\aspectjweaver-1.9.5.jar;C:\xzRepository\org\springframework\spring-orm\5.2.3.RELEASE\spring-orm-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-jdbc\5.2.3.RELEASE\spring-jdbc-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-tx\5.2.3.RELEASE\spring-tx-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\boot\spring-boot-starter-web\2.2.3.RELEASE\spring-boot-starter-web-2.2.3.RELEASE.jar;C:\xzRepository\org\springframework\boot\spring-boot-starter\2.2.3.RELEASE\spring-boot-starter-2.2.3.RELEASE.jar;C:\xzRepository\org\springframework\boot\spring-boot\2.2.3.RELEASE\spring-boot-2.2.3.RELEASE.jar;C:\xzRepository\org\springframework\boot\spring-boot-autoconfigure\2.2.3.RELEASE\spring-boot-autoconfigure-2.2.3.RELEASE.jar;C:\xzRepository\org\springframework\boot\spring-boot-starter-logging\2.2.3.RELEASE\spring-boot-starter-logging-2.2.3.RELEASE.jar;C:\xzRepository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\xzRepository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\xzRepository\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;C:\xzRepository\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;C:\xzRepository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;C:\xzRepository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\xzRepository\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;C:\xzRepository\org\springframework\boot\spring-boot-starter-json\2.2.3.RELEASE\spring-boot-starter-json-2.2.3.RELEASE.jar;C:\xzRepository\com\fasterxml\jackson\core\jackson-databind\2.10.2\jackson-databind-2.10.2.jar;C:\xzRepository\com\fasterxml\jackson\core\jackson-annotations\2.10.2\jackson-annotations-2.10.2.jar;C:\xzRepository\com\fasterxml\jackson\core\jackson-core\2.10.2\jackson-core-2.10.2.jar;C:\xzRepository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.2\jackson-datatype-jdk8-2.10.2.jar;C:\xzRepository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.2\jackson-datatype-jsr310-2.10.2.jar;C:\xzRepository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.2\jackson-module-parameter-names-2.10.2.jar;C:\xzRepository\org\springframework\boot\spring-boot-starter-tomcat\2.2.3.RELEASE\spring-boot-starter-tomcat-2.2.3.RELEASE.jar;C:\xzRepository\org\apache\tomcat\embed\tomcat-embed-core\9.0.30\tomcat-embed-core-9.0.30.jar;C:\xzRepository\org\apache\tomcat\embed\tomcat-embed-el\9.0.30\tomcat-embed-el-9.0.30.jar;C:\xzRepository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.30\tomcat-embed-websocket-9.0.30.jar;C:\xzRepository\org\springframework\boot\spring-boot-starter-validation\2.2.3.RELEASE\spring-boot-starter-validation-2.2.3.RELEASE.jar;C:\xzRepository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;C:\xzRepository\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;C:\xzRepository\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;C:\xzRepository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;C:\xzRepository\org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-webmvc\5.2.3.RELEASE\spring-webmvc-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-aop\5.2.3.RELEASE\spring-aop-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-context\5.2.3.RELEASE\spring-context-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\spring-expression\5.2.3.RELEASE\spring-expression-5.2.3.RELEASE.jar;C:\xzRepository\org\springframework\boot\spring-boot-starter-test\2.2.3.RELEASE\spring-boot-starter-test-2.2.3.RELEASE.jar;C:\xzRepository\org\springframework\boot\spring-boot-test\2.2.3.RELEASE\spring-boot-test-2.2.3.RELEASE.jar;C:\xzRepository\org\springframework\boot\spring-boot-test-autoconfigure\2.2.3.RELEASE\spring-boot-test-autoconfigure-2.2.3.RELEASE.jar;C:\xzRepository\com\jayway\jsonpath\json-path\2.4.0\json-path-2.4.0.jar;C:\xzRepository\net\minidev\json-smart\2.3\json-smart-2.3.jar;C:\xzRepository\net\minidev\accessors-smart\1.2\accessors-smart-1.2.jar;C:\xzRepository\org\ow2\asm\asm\5.0.4\asm-5.0.4.jar;C:\xzRepository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\xzRepository\jakarta\xml\bind\jakarta.xml.bind-api\2.3.2\jakarta.xml.bind-api-2.3.2.jar;C:\xzRepository\jakarta\activation\jakarta.activation-api\1.2.1\jakarta.activation-api-1.2.1.jar;C:\xzRepository\org\junit\jupiter\junit-jupiter\5.5.2\junit-jupiter-5.5.2.jar;C:\xzRepository\org\junit\jupiter\junit-jupiter-api\5.5.2\junit-jupiter-api-5.5.2.jar;C:\xzRepository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\xzRepository\org\junit\platform\junit-platform-commons\1.5.2\junit-platform-commons-1.5.2.jar;C:\xzRepository\org\junit\jupiter\junit-jupiter-params\5.5.2\junit-jupiter-params-5.5.2.jar;C:\xzRepository\org\junit\jupiter\junit-jupiter-engine\5.5.2\junit-jupiter-engine-5.5.2.jar;C:\xzRepository\org\junit\vintage\junit-vintage-engine\5.5.2\junit-vintage-engine-5.5.2.jar;C:\xzRepository\org\apiguardian\apiguardian-api\1.1.0\apiguardian-api-1.1.0.jar;C:\xzRepository\org\junit\platform\junit-platform-engine\1.5.2\junit-platform-engine-1.5.2.jar;C:\xzRepository\junit\junit\4.12\junit-4.12.jar;C:\xzRepository\org\mockito\mockito-junit-jupiter\3.1.0\mockito-junit-jupiter-3.1.0.jar;C:\xzRepository\org\assertj\assertj-core\3.13.2\assertj-core-3.13.2.jar;C:\xzRepository\org\hamcrest\hamcrest\2.1\hamcrest-2.1.jar;C:\xzRepository\org\mockito\mockito-core\3.1.0\mockito-core-3.1.0.jar;C:\xzRepository\net\bytebuddy\byte-buddy\1.10.6\byte-buddy-1.10.6.jar;C:\xzRepository\net\bytebuddy\byte-buddy-agent\1.10.6\byte-buddy-agent-1.10.6.jar;C:\xzRepository\org\objenesis\objenesis\2.6\objenesis-2.6.jar;C:\xzRepository\org\skyscreamer\jsonassert\1.5.0\jsonassert-1.5.0.jar;C:\xzRepository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;C:\xzRepository\org\springframework\spring-test\5.2.3.RELEASE\spring-test-5.2.3.RELEASE.jar;C:\xzRepository\org\xmlunit\xmlunit-core\2.6.3\xmlunit-core-2.6.3.jar;C:\xzRepository\com\alibaba\fastjson\2.0.33\fastjson-2.0.33.jar;C:\xzRepository\com\alibaba\fastjson2\fastjson2-extension\2.0.33\fastjson2-extension-2.0.33.jar;C:\xzRepository\com\alibaba\fastjson2\fastjson2\2.0.33\fastjson2-2.0.33.jar;C:\xzRepository\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;C:\xzRepository\cn\hutool\hutool-all\5.8.19\hutool-all-5.8.19.jar;C:\xz\code\pa-ai-common\nas-config-client\target\classes;C:\xzRepository\org\springframework\cloud\spring-cloud-starter\2.2.0.RELEASE\spring-cloud-starter-2.2.0.RELEASE.jar;C:\xzRepository\org\springframework\cloud\spring-cloud-context\2.2.0.RELEASE\spring-cloud-context-2.2.0.RELEASE.jar;C:\xzRepository\org\springframework\security\spring-security-crypto\5.2.1.RELEASE\spring-security-crypto-5.2.1.RELEASE.jar;C:\xzRepository\org\springframework\cloud\spring-cloud-commons\2.2.0.RELEASE\spring-cloud-commons-2.2.0.RELEASE.jar;C:\xzRepository\org\springframework\security\spring-security-rsa\1.0.7.RELEASE\spring-security-rsa-1.0.7.RELEASE.jar;C:\xzRepository\org\bouncycastle\bcpkix-jdk15on\1.60\bcpkix-jdk15on-1.60.jar;C:\xzRepository\org\bouncycastle\bcprov-jdk15on\1.60\bcprov-jdk15on-1.60.jar;C:\xzRepository\com\squareup\okhttp3\okhttp\3.12.0\okhttp-3.12.0.jar;C:\xzRepository\com\squareup\okio\okio\1.15.0\okio-1.15.0.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2022.2.3\lib\idea_rt.jar" com.pingan.lcloud.stack.DeadLockDemo
Connected to the target VM, address: '127.0.0.1:4226', transport: 'socket'
Thread[线程 1,5,main]get resource1
Thread[线程 2,5,main]get resource2
Thread[线程 1,5,main]waiting get resource2
Thread[线程 2,5,main]waiting get resource1

打印快照

java
# win下找到java进程
tasklist | findstr "java"
# 打印快照, 注意win环境下需要再将txt文件转为utf-8编码
jstack -l 1396 > C:\xz\tool\0712.txt

使用JCA打开快照

java
java -jar jca4614.jar

1745408566271

检测到死锁

1745408572003

分析热点线程案例

  1. 先通过top -Hp <PID>找到java进程中占用CPU资源较高的线程id
  2. 使用printf "%x" <id>将id转为16进制
  3. 打印线程快照, 找到该id对应的线程在执行的代码, 即可定位到具体的问题

参考