Loading... # 一、Thread Dump日志分析 接下来给大家再讲点在工作中比较实用的一个内容。就是我们在使用线程的时候,如果出现问题,怎么 排查?比如说 - CPU占用率很高,响应很慢 - CPU占用率不高,但响应很慢 - 线程出现死锁的情况 ## 演示代码 为了更好的体现效果,我们通过以下代码进行演示。 编写一个java项目 ```java /** * 控制器接口层 **/ @RestController public class ThreadController { @GetMapping("/loop") public String dumpWhile(){ new Thread(new WhileThread()).start(); return "ok"; } @GetMapping("/dead") public String dumpDeadLock(){ Thread a = new ThreadRunA(); Thread b = new ThreadRunB(); a.start(); b.start(); return "ok"; } } class WhileThread implements Runnable { @Override public void run() { while (true) { System.out.println("Thread"); } } } ``` ```java /** * 线程A **/ class ThreadRunA extends Thread { @Override public void run() { System.out.println("================A==================="); synchronized (A.A) { System.out.println("我要开始执行任务A。。。。" + Thread.currentThread().getName()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (B.B) { } System.out.println("我在执行任务结束了A。。。。" + Thread.currentThread().getName() + ":" + B.B.hashCode() + ":" + A.A.hashCode()); } } } ``` ```java /** * 线程B **/ class ThreadRunB extends Thread { @Override public void run() { System.out.println("================B==================="); synchronized (B.B) { System.out.println("我要开始执行任务B。。。。" + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (A.A) { } System.out.println("我在执行任务结束了B。。。。" + Thread.currentThread().getName() + ":" + B.B + ":" + A.A); } } } ``` ```shell nohup java -jar -Dserver.port=8088 thread-demo-0.0.1-SNAPSHOT.jar > all.log & //打成jar后运行 ``` ## CPU占用率不高,但响应很慢 通过 curl http://127.0.0.1:8088/dead 演示死锁的场景 查看死锁问题的操作步骤如下: - 通过 jps命令,查看java进程的pid - 通过 jstack 查看线程日志 如果存在死锁情况,Thread Dump 日志里面肯定会给出 Found one Java-level deadlock:信息。只要 找到这个信息就可以立马定位到问题并且去解决。 ```java Found one Java-level deadlock: ============================= "Thread-1": waiting to lock monitor 0x0000000026070c88 (object 0x00000007163b7d78, a java.lang.Integer), which is held by "Thread-0" "Thread-0": waiting to lock monitor 0x00000000260735c8 (object 0x0000000716649aa8, a java.lang.Integer), which is held by "Thread-1" ``` ## CPU占用率很高,响应很慢 有的时候我们会发现CPU占用率很高,系统日志也看不出问题,那么这种情况下,我们需要去看一下运 行中的线程有没有异常。 执行 curl http://127.0.0.1:8088/loop这个方法,会出现一个线程死循环的情况。 - 通过 top -c 动态显示进程及占用资源的排行榜,从而找到占用CPU最高的进程PID,得到的 **PID=80972** ```shell PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 80972 root 20 0 7773456 296124 12904 S 100.2 1.8 0:38.83 java ``` - 然后再定位到对应的线程, top -H -p 80972 查找到该进程中最消耗CPU的线程,得到 **PID=81122** ```shell PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 81122 root 20 0 7773456 258504 12932 R 99.8 1.6 5:56.34 java 80972 root 20 0 7773456 258504 12932 S 0.0 1.6 0:00.00 java ``` - 通过 printf "0x%x\n" 81122 命令,把对应的线程PID转化为16进制 ```shell [root@localhost test]# printf "0x%x\n" 81122 0x13ce2 ``` - 截止执行这个命令 jstack 80972 | grep -A 20 0x13ce2 查看线程Dump日志,其中-A 20表示展示20行, 80972表示进程ID, 0x13ce2表示线程ID ![](/images/img-130.png) 从上述内容可以看出,是WhileThread.run方法中,执行的逻辑导致CPU占用过高。 最后修改:2022 年 06 月 23 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请点个赞吧~