要分析Tomcat的线程状态,首先需要获取其进程ID。在Ubuntu终端中执行以下命令:
pgrep -f tomcat
或通过ps
命令过滤:
ps -ef | grep tomcat | grep -v grep | awk '{print $2}'
输出的数字即为Tomcat的主进程ID(如12345
)。
线程转储是诊断死锁的核心工具,它记录了所有线程的状态、堆栈轨迹及锁持有情况。在Ubuntu中,可通过以下两种方式生成:
jstack
命令(需JDK环境)jstack -l <Tomcat_PID> > /var/log/tomcat/thread_dump_$(date +%F_%T).log
其中-l
参数会额外打印锁的附加信息(如java.lang.Thread.State: BLOCKED
的锁定对象),有助于定位死锁根源。SIGQUIT
信号(无需额外工具)kill -3 <Tomcat_PID>
该命令会将线程转储输出到Tomcat的默认日志文件catalina.out
中(路径通常为/var/log/tomcat/catalina.out
)。生成线程转储后,需通过关键词快速定位死锁信息:
grep
命令在转储文件中查找“deadlock”(不区分大小写),若存在死锁,日志会明确提示:grep -i "deadlock" /var/log/tomcat/thread_dump_$(date +%F_%T).log
示例输出:Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00007f8a1c003ae8 (object 0x000000076b5b6b98, a java.lang.Object),
which is held by "Thread-2"
"Thread-2":
waiting to lock monitor 0x00007f8a1c004b28 (object 0x000000076b5b6ba8, a java.lang.Object),
which is held by "Thread-1"
上述输出清晰展示了死锁线程(Thread-1
和Thread-2
)及它们互相等待的锁对象。BLOCKED
(阻塞)状态,且堆栈中包含waiting to lock
或- locked
字样。例如:"Thread-1" #11 prio=5 os_prio=0 tid=0x00007f8a1c001000 nid=0x1e34 waiting for monitor entry [0x00007f8a0a7fe000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.DeadlockExample.methodA(DeadlockExample.java:20)
- waiting to lock <0x000000076b5b6b98> (a java.lang.Object)
at com.example.DeadlockExample.run(DeadlockExample.java:15)
结合多个线程的BLOCKED
状态及锁依赖关系(如Thread-1
等待Thread-2
持有的锁,Thread-2
又等待Thread-1
持有的锁),可推断出死锁。locked
或waiting to lock
后面的对象地址(如0x000000076b5b6b98
),相同地址的对象是线程争夺的核心。com.example.DeadlockExample.methodA
),便于后续修复。Thread-1
先锁ObjectA
再锁ObjectB
,Thread-2
先锁ObjectB
再锁ObjectA
),易引发死锁,需调整锁获取顺序。通过以上步骤,可在Ubuntu系统的Tomcat日志中有效查找并定位线程死锁问题。若需更直观的分析,可将线程转储导入在线工具(如fastthread.io),自动解析死锁及线程状态。