查看SpringBoot當(dāng)前線程數(shù)的3種有效方法
前幾天,我在排查一個 SpringBoot 應(yīng)用響應(yīng)變慢的問題。日志看不出有什么異常,CPU和內(nèi)存也還算正常,但用戶就是覺得卡。
于是,我在想:是不是某個線程卡住了,或者線程池失控了?現(xiàn)在到底有多少線程在運(yùn)行?
好在查看線程數(shù)并不復(fù)雜,不管是臨時診斷還是長期監(jiān)控,都有現(xiàn)成的辦法。下面我就分享幾種常用的方式。
監(jiān)控方案
| 監(jiān)控方式 | 適用場景 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|---|
| Spring Boot Actuator | 生產(chǎn)環(huán)境監(jiān)控 | 集成度高,RESTful接口 | 需要添加依賴和配置 |
| jstack命令 | 緊急問題診斷 | JDK自帶,無需配置 | 命令行操作,不夠直觀 |
| VisualVM | 開發(fā)測試環(huán)境 | 圖形化界面,功能強(qiáng)大 | JDK 9+需要單獨(dú)安裝 |
| JMC | 生產(chǎn)環(huán)境深度分析 | 性能分析強(qiáng)大 | 內(nèi)存占用較高 |
下面我們看看前3種方案是怎么使用的。
一、Spring Boot自帶監(jiān)控(最簡單)
步驟1:添加依賴
<!-- 在pom.xml中添加 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
步驟2:修改配置
# 在application.yml中添加
management:
endpoints:
web:
exposure:
include: "metrics,threaddump"
步驟3:啟動項(xiàng)目后,查看線程信息
# 查看線程總數(shù) http://127.0.0.1:8080/actuator/metrics/jvm.threads.live
如圖

measurement.value 就是當(dāng)前存活的線程數(shù),配置簡單,不用記命令。
安全配置(生產(chǎn)環(huán)境)
spring:
security:
user:
name: admin
password: securepassword
management:
server:
port: 9090 # 監(jiān)控端口與業(yè)務(wù)端口分離
二、使用jstack命令(最常用)
1. 找到應(yīng)用ID
# 查看所有Java進(jìn)程 jps -l # 或者使用ps命令 ps aux | grep java
輸出類似:
36756 org.springframework.boot.loader.JarLauncher
如圖:

2. 分析線程
jstack 36756
如圖:

線程狀態(tài)說明
- RUNNABLE: 線程正在運(yùn)行或準(zhǔn)備運(yùn)行
- WAITING: 無限期等待其他線程的特定操作
- TIMED_WAITING: 有限時間等待
- BLOCKED: 等待獲取監(jiān)視器鎖
- TERMINATED: 線程已結(jié)束
關(guān)鍵線程類型識別
1. JVM系統(tǒng)線程
"Reference Handler" - 引用處理線程 "Finalizer" - 對象終結(jié)線程 "Signal Dispatcher" - 信號分發(fā)線程 "GC Thread" - 垃圾回收線程(多個)
2. Spring Boot應(yīng)用線程
"http-nio-8080-exec-*" - Tomcat工作線程 "Catalina-utility-*" - Tomcat工具線程 "HikariPool-*" - 數(shù)據(jù)庫連接池線程
3. 第三方庫線程
"lettuce-*" - Redis客戶端線程 "boundedElastic-*" - Reactor響應(yīng)式線程 "mysql-cj-*" - MySQL驅(qū)動線程
3. 線程快照
也可以生成線程快照,保存到文件后再慢慢分析
jstack 36756 > thread.txt
快速統(tǒng)計(jì)命令:
# 統(tǒng)計(jì)總線程數(shù) grep 'java.lang.Thread.State' thread.txt | wc -l # 統(tǒng)計(jì)Tomcat線程數(shù) grep '"http-nio' thread.txt | wc -l # 查看線程狀態(tài)分布 grep 'java.lang.Thread.State' thread.txt | sort | uniq -c
也可以通過自動化監(jiān)控腳本進(jìn)行分析
#!/bin/bash
# monitor_threads.sh
APP_NAME="your-spring-boot-app"
LOG_DIR="./thread_dumps"
INTERVAL=60 # 監(jiān)控間隔(秒)
MAX_DUMPS=10 # 最大轉(zhuǎn)儲文件數(shù)
mkdir -p $LOG_DIR
while true; do
PID=$(jps -l | grep $APP_NAME | awk '{print $1}')
if [ -z "$PID" ]; then
echo "$(date): 應(yīng)用未運(yùn)行"
sleep $INTERVAL
continue
fi
# 生成時間戳
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# 生成線程轉(zhuǎn)儲
jstack $PID > $LOG_DIR/thread_dump_$TIMESTAMP.txt
# 統(tǒng)計(jì)線程信息
TOTAL_THREADS=$(grep 'java.lang.Thread.State' $LOG_DIR/thread_dump_$TIMESTAMP.txt | wc -l)
RUNNABLE=$(grep 'java.lang.Thread.State: RUNNABLE' $LOG_DIR/thread_dump_$TIMESTAMP.txt | wc -l)
WAITING=$(grep 'java.lang.Thread.State: WAITING' $LOG_DIR/thread_dump_$TIMESTAMP.txt | wc -l)
BLOCKED=$(grep 'java.lang.Thread.State: BLOCKED' $LOG_DIR/thread_dump_$TIMESTAMP.txt | wc -l)
echo "$(date): 線程統(tǒng)計(jì) - 總數(shù): $TOTAL_THREADS, 運(yùn)行: $RUNNABLE, 等待: $WAITING, 阻塞: $BLOCKED"
# 清理舊文件
ls -t $LOG_DIR/thread_dump_*.txt | tail -n +$MAX_DUMPS | xargs rm -f
sleep $INTERVAL
done
優(yōu)點(diǎn):不用改代碼,隨時可用
三、使用VisualVM(最直觀)
1. 安裝步驟
- 訪問 visualvm.github.io/
- 下載對應(yīng)版本
- 解壓后運(yùn)行
bin/visualvm
2. 使用方法
- 啟動VisualVM
# Windows visualvm.exe # Linux/macOS ./visualvm
- 在左邊找到你的應(yīng)用
- 點(diǎn)擊應(yīng)用名稱就能看到基礎(chǔ)信息頁了
如圖

Monitor 監(jiān)控頁

界面說明
- CPU使用率:查看方法執(zhí)行時間
- 堆內(nèi)存使用:監(jiān)控內(nèi)存泄漏
- Metaspace:JDK 17中的元數(shù)據(jù)空間
- 類加載數(shù)量
- 線程數(shù):實(shí)時查看線程創(chuàng)建和銷毀
Threads 線程標(biāo)簽頁(最重要)

界面說明
- 實(shí)時查看所有線程狀態(tài)
- 顏色標(biāo)識:
- 綠色:運(yùn)行中 (RUNNABLE)
- 黃色:等待 (WAITING, TIMED_WAITING)
- 紅色:阻塞 (BLOCKED)
- 可以生成線程轉(zhuǎn)儲(相當(dāng)于jstack)
這里可以查看線程的詳細(xì)信息

詳細(xì)信息內(nèi)容看到的就和我們上面執(zhí)行的結(jié)果是一樣的,需要的話可以復(fù)制下來保存到本地

3. 遠(yuǎn)程監(jiān)控配置
應(yīng)用端配置
啟動Spring Boot時添加JMX參數(shù):
java -Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=9090 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.local.only=false \
-Djava.rmi.server.hostname=你的服務(wù)器IP \
-jar your-app.jar
VisualVM連接配置
- 右鍵"遠(yuǎn)程" → "添加遠(yuǎn)程主機(jī)"
- 輸入主機(jī)名或IP地址
- 右鍵遠(yuǎn)程主機(jī) → "添加JMX連接"
- 輸入端口號(9090)
優(yōu)點(diǎn):圖形界面,一目了然
四、問題排查案例
案例1:應(yīng)用變慢
# 1. 生成線程快照 jstack 36756 > slow.txt # 2. 查看有沒有BLOCKED線程 grep "BLOCKED" slow.txt # 3. 查看Tomcat線程在干什么 grep -A 5 "http-nio" slow.txt
案例2:內(nèi)存占用高
# 查看線程總數(shù)是否異常 grep 'java.lang.Thread.State' thread.txt | wc -l
正常:30-100個線程 異常:超過500個線程
案例3:應(yīng)用無響應(yīng)
# 強(qiáng)制生成線程快照 jstack -F 36756 > stuck.txt # 查找死鎖 grep -i "deadlock" stuck.txt
總結(jié)
如果你在開發(fā)或測試階段,想快速直觀地了解線程狀態(tài),VisualVM 是最友好的選擇。
如果你正在線上排查問題,又不方便改代碼或重啟服務(wù),jstack 這類 JDK 自帶命令就是你的急救包,輕量、不需要其它依賴。
而如果你已經(jīng)部署了監(jiān)控體系,那么 SpringBoot Actuator 不僅能告訴你線程數(shù)量,還能集成到 Prometheus、Grafana 等監(jiān)控平臺,實(shí)現(xiàn)自動化告警。
以上就是查看SpringBoot當(dāng)前線程數(shù)的3種有效方法的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot當(dāng)前線程數(shù)查看的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java對list集合進(jìn)行分頁的四種寫法總結(jié)
這篇文章主要介紹了java對list集合進(jìn)行分頁的四種寫法總結(jié),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-05-05
詳解Spring Cloud Zuul網(wǎng)關(guān)修改為短連接方法
本文主要介紹了詳解Spring Cloud Zuul網(wǎng)關(guān)修改為短連接方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
Eclipse創(chuàng)建java程序可執(zhí)行jar包教程
這篇文章主要為大家分享了Eclipse創(chuàng)建java程序可執(zhí)行jar包教程,具有一定的實(shí)用性和參考價值,感興趣的小伙伴們可以參考一下2016-05-05
深入學(xué)習(xí)java ThreadLocal的源碼知識
ThreadLocal是一個本地線程副本變量工具類。主要用于將私有線程和該線程存放的副本對象做一個映射,各個線程之間的變量互不干擾,特別適用于各個線程依賴不通的變量值完成操作的場景。下面我們來詳細(xì)了解一下它吧2019-06-06

