如何通过命令行终止Java程序中处于死锁状态的线程?
死锁线程临时终止方案
方案一:使用Arthas在线诊断工具(无需提前开启JMX,无需修改代码)
Arthas是开源Java线上诊断工具,可直接attach到运行中的Java进程,全命令行操作,无侵入:
- 自行搜索下载Arthas的arthas-boot.jar包,执行启动命令:
执行后会列出当前运行的所有Java进程,输入你要处理的进程编号回车即可attach成功。java -jar arthas-boot.jar - 定位死锁线程:
执行命令thread -b,会直接输出持有锁导致其他线程阻塞的死锁线程,也可以执行thread命令查看所有线程,和之前SIGQUIT输出的死锁线程名对应,记录要终止的线程的十进制ID。 - 终止目标线程:
执行命令stop {线程ID},即可终止指定死锁线程,该线程持有的所有synchronized锁会自动释放,剩余存活的死锁线程即可拿到锁继续执行。
方案二:使用JDK原生JMX能力(无第三方工具依赖)
如果不能引入第三方工具,可以临时开启JMX实现线程终止:
- 给目标Java进程添加JMX启动参数后重启(仅适合允许临时重启的场景):
java -Dcom.sun.management.jmxremote.port=12345 \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -Djava.rmi.server.hostname=本机IP \ 你原来的启动命令
- 自行搜索下载CLI版JMX客户端jmxterm的uber jar包,执行连接命令:
java -jar jmxterm-xxx-uber.jar -l service:jmx:rmi:///jndi/rmi://本机IP:12345/jmxrmi
- 定位到Thread MBean,找到对应死锁线程的ID,调用
stop操作即可终止线程。
注意事项
- 针对示例中的synchronized锁场景,线程
interrupt()方法是无效的,因为synchronized锁等待不会响应中断信号,只有显式使用java.util.concurrent.locks.Lock的lockInterruptibly()方法拿锁的场景才能用中断解开死锁,所以救急场景只能用废弃的Thread.stop()方法。 - 终止线程会导致该线程正在操作的共享对象状态可能出现不一致,仅作为上线修复版前的临时救急方案,后续修复完死锁逻辑后一定要完整重启应用进程,避免脏数据扩散。
内容的提问来源于stack exchange,提问作者joseph
相关产品推荐
相关产品推荐

