IDE 除錯器適合圖形化應用,但無法有效除錯多執行緒 Java 伺服器程式。幸運的是,可透過 Ctrl+\(Linux/Unix)或 Ctrl+Break(Windows)獲取系統執行緒傾印,即時觀察 JVM 狀態。
Full thread dump:
"Thread-1" prio=5 tid=0x87fe0 nid=0x800013b8 waiting on monitor [0..0xbfffe9f8]
"Thread-0" prio=5 tid=0xafde0 nid=0x72a00 runnable [0x173f000..0x173fb48]
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:421)
at java.net.ServerSocket.implAccept(ServerSocket.java:243)
at java.net.ServerSocket.accept(ServerSocket.java:222)
at com.generationjava.net.PortListener.run(PortListener.java:38)
at java.lang.Thread.run(Thread.java:496)
"Signal Dispatcher" daemon prio=10 tid=0xa5f80 nid=0x52af0 waiting on monitor [0..0]
"Finalizer" daemon prio=8 tid=0xa46c0 nid=0x4d930 waiting on monitor [0x10a8000..0x10a8b48]
at java.lang.Object.wait(Native Method)
...
"VM Thread" prio=5 tid=0xa2de0 nid=0x4ca20 runnable
"VM Periodic Task Thread" prio=10 tid=0xa56b0 nid=0x52890 waiting on monitor
"Thread-0"、"Finalizer" 等prio=5runnable、waiting on monitorServerSocket.accept())後四個為標準守護執行緒,前兩個為應用業務執行緒(預設命名 Thread-0、Thread-1)。
// 替代 new Thread(runnable)
Thread th = new Thread(runnable, "Server");
th.setName("Server");
// 未命名
"Thread-0" prio=5 ... runnable ...
// 命名後
"Server" prio=5 ... runnable ...
命名後可立即識別業務角色,避免在大量執行緒中盲目猜測。
模組-角色-序號(例:Order-Processor-3)jstack、VisualVM、JConsole、Arthas、Java Flight Recorder| 堆疊特徵 | 可能問題 |
|---|---|
大量 waiting on monitor 且鎖持有者長時間 runnable | 鎖競爭、死鎖、長時間關鍵區 |
socketAccept/socketRead 大量堆疊 | 網路 I/O 瓶頸、連線洩漏 |
Object.wait() 無超時 | 通知遺失、條件變數誤用 |
| GC 執行緒頻繁佔用高 CPU | 記憶體壓力、物件分配率過高 |
ThreadFactory 統一命名