一、線程死鎖
線程死鎖就是有兩個以上的線程,一個線程鎖住了資源A,又想去鎖定資源B,另外一個線程鎖定了資源B,又想去鎖定資源A,兩個線程都想去得到對方的資源,而又不願釋放自己的資源
從而造成一種互相等待,無法執行的情況
接口:http://localhost:8080/PerfTeach/DeadServlet
因為要出現線程死鎖至少要2個用戶,所以用3個並發,永遠跑
TPS:
響應時間
使用jstat -gcutil查看,JVM正常
使用dstat -tcdlmnsygr查看,cpu沒什么壓力
通過瀏覽器訪問接口,沒有響應
jvisualvm查看
jstack查看:使用jstack把堆棧日志打印到a.log里面
打開直接翻到最后,第8、4、7個線程出現死鎖,並且會在下面把這三個線程拿出來打印
出現死鎖的位置和原因:
所以是線程7鎖定了資源,然后線程8和4在等待線程7解鎖
看一下代碼:出現了嵌套鎖
現象:出現死鎖后,tps降為0,壓力測試工具無法得到服務器的響應,服務器硬件資源空閑,通過jvisualvm去查看線程情況,至少兩個線程一直處於紅色的阻塞狀態
死鎖經常表現為程序的停頓,或者不再響應用戶的請求。從操作系統上觀察,對應進程的CPU占用率為零
解鎖辦法:重啟tomcat
定位方法:通過jvisualvm或者jstack,進行線程dump,對線程狀態進行分析,獲取到哪行代碼導致的死鎖,如:
Found one Java-level deadlock:
http-bio-8080"-exec-162":
waiting to lock monitor 0x0818abac (object 0x84b40ad0, a com.lee.domain.Order),
which is held by ""http-bio-8080"-exec-158"
""http-bio-8080"-exec-158":
waiting to lock monitor 0x08188cd0 (object 0x84b3bc48, a com.lee.domain.Order),
which is held by ""http-bio-8080"-exec-162"
Java stack information for the threads listed above:
死鎖一般解決思路:
1、避免嵌套加鎖
2、減小鎖粒度,鎖越少越不容易發生死鎖
二、線程阻塞
線程阻塞問題-log4j日志級別問題
接口:http://localhost:8080/PerfTeach/Block?userId=1
30個並發永遠跑,dstat監控起來:dstat -tcdlmnsygr --disk-util
從資源上看,問題不大
TPS:550左右
響應時間:46左右
一般在項目中發現響應式時間長,監控一下線程
右上角Dump,多Dump幾次,這里Dump3次,然后把3個快照里面的內容分別復制3個文本里面,直接ctrl+f搜BLOCKED
代碼里面這一行在打印日志
log4j代碼里面有鎖
解決方案:
1、還是用log4j,但是把日志打印級別提高,在代碼里面減少不必要的日志打印輸出
2、換其他日志組件如:log4j2、logback
log4j.xml中設置的日志級別,程序會打印在此級別之上日志
Error、Warn、Info、debug,級別越低,日志越多
cd /home/apps/app-PerfTeach/PerfTeach/WEB-INF/classes/
vi log4j.xml
默認打印級別是debug,改為error
重啟tomcat
還是30個並發,永遠跑
看一下tomcat下的日志
cd /home/server/tomcat-PerfTeach01/bin/D\:/
tail -f output.log
全是error級別的
TPS:900左右
響應時間:40左右
和剛才相比,TPS和響應時間都有明顯的提升,由於配置比較低,這里提升不明顯,真實公司里面的配置,最少提升2--3倍
從線程監控看,阻塞情況減少很多了,這個阻塞情況是因為打印error的日志
線程問題排查流程:
1、做線程dump
2、在dump文件中搜索關鍵字"BLOCKED"、"TIME_WAITTING",查看每種狀態的count數量
3、按照上述關鍵字搜索,查看跟本系統有關的業務代碼堆棧信息