- Java并發編程深度解析與實戰
- 譚鋒(Mic)
- 1044字
- 2022-05-10 18:39:15
1.11 快速定位并解決線程導致的生產問題
在使用多線程時,如果使用不當,就會產生一些問題,比如:
? 死鎖導致請求無法響應。
? CPU占用率很高,響應很慢。
學完本章的內容之后,是否能夠解決這些問題呢?
我們先來創建一個Spring Boot應用,模擬一個死鎖問題和CPU占用率過高的問題,核心代碼如下。



1.11.1 死鎖導致請求無法響應
將上面的這段程序運行后,使用如下命令制造死鎖場景:

對于死鎖問題的排查,具體操作步驟如下:
第一步,通過jps命令,查看Java進程的pid。
第二步,通過jstack <pid>命令查看線程dump日志。
當發現死鎖時,可以在打印的dump日志中找到Found one Java-level deadlock:信息,根據信息的內容分析問題出現的原因。

jstack是Java虛擬機自帶的一種堆棧跟蹤工具,它主要用于打印指定Java進程ID中當前時刻的線程dump日志,線程快照是當前Java虛擬機內每一條線程正在執行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現長時間停頓的原因,如線程間死鎖、死循環、請求外部資源導致的長時間等待等,語法格式如下。

1.11.2 CPU占用率很高,響應很慢
為了演示CPU過高的場景,先執行如下命令,這個命令會讓線程進入死循環狀態。

上述命令運行完后,通過top -c命令可以動態顯示進程及其占用資源的排行榜,從該結果中可以找到占用CPU最高的進程PID。

可以看到,CPU占用率100%的PID是80972,定位到該進程之后,我們再從線程的dump日志中去定位。
? 使用top -H -p 80972命令查找到該進程中消耗CPU最多的線程,從下面的打印結果中發現PID=81122的線程CPU占用率最高。

? 通過printf "0x%x\n" 81122命令把對應的線程PID轉化為16進制進行打印,之所以要做這步操作是因為線程dump日志中是以16進制來顯示線程PID的。

? 執行jstack命令,打印PID=80972進程的線程dump日志,然后通過管道命令grep從線程dump日志中查找到CPU占用率最高的線程。

-A表示顯示匹配行及其后面的n行。
通過上述操作后,得到的線程dump信息如下,從該信息中我們發現,在WhileThread.run()方法中因為某個操作導致CPU占用率過高,于是基于這個信息我們可以進行分析從而解決該問題。


上述代碼內容其實可以分為三個部分。
? 線程的基本信息:"Thread-3" #30 daemon prio=5 os_prio=0 tid=0x00007f84500ce000 nid=0x13ce2 runnable [0x00007f84a78f7000]。
○ Thread-3表示線程名字,為了更好地辨別,建議大家在使用線程的時候自己進行命名。
○ #30,線程的編號。
○ daemon,表示守護線程。
○ prio,線程的優先級,Java中的線程優先級分為1~10個級別,數字越高表示優先級越高,優先級高的線程能夠有更高的概率優先得到CPU的執行。
○ os_prio,表示操作系統層面的線程優先級,Java中配置的線程優先級最終會映射到操作系統中的線程優先級。
○ tid=0x00007f84500ce000,JVM內部線程ID。
○ nid,系統線程ID
○ runnable,線程狀態。
? 線程的運行狀態,java.lang.Thread.State: RUNNABLE。
? 線程的堆棧信息,該信息可以用來快速定位具體的執行指令。
- 解構產品經理:互聯網產品策劃入門寶典
- TypeScript入門與實戰
- Building an RPG with Unity 2018
- Linux Device Drivers Development
- Learning Three.js:The JavaScript 3D Library for WebGL
- Extreme C
- Python從入門到精通
- 測試架構師修煉之道:從測試工程師到測試架構師
- Data Science Algorithms in a Week
- 寫給青少年的人工智能(Python版·微課視頻版)
- Learning Shiny
- React and React Native
- 基于JavaScript的WebGIS開發
- Learning Azure DocumentDB
- Hands-On Artificial Intelligence with Unreal Engine