官术网_书友最值得收藏!

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。

? 線程的堆棧信息,該信息可以用來快速定位具體的執行指令。

主站蜘蛛池模板: 房山区| 丹东市| 嘉义县| 连城县| 平泉县| 三门峡市| 尼玛县| 宕昌县| 辽宁省| 尚志市| 谷城县| 丹巴县| 航空| 闻喜县| 遂平县| 海原县| 敖汉旗| 江孜县| 天津市| 黑龙江省| 泰来县| 阿克苏市| 崇信县| 宁城县| 建德市| 宜君县| 墨玉县| 依安县| 天门市| 吉安县| 乌鲁木齐市| 西乌| 桑日县| 清流县| 平顺县| 静安区| 仙桃市| 博野县| 安顺市| 酒泉市| 衡阳市|