性能问题之线程死锁
定义
线程死锁就是有两个线程,一个线程锁住了资源A,又想去锁住资源B,另外一个线程锁定了资源B,又想去锁定资源A,两个线程都想去得到对方的资源而又不愿意释放自己的资源,从而造成了一种互相等待、无法执行的情况。
现象
出现死锁后,TPS降为0,性能测试工具无法得到服务器的响应,
服务器硬件资源空闲
通过jvisualvm去查看线程情况,至少两个线程一直处于红色的阻塞状态
案例分析
1、某接口压测5分钟结果如下:
从上面三幅图片可以看出:
(1)从测试工具jmeter可以看出,5分钟还未到,测试过程还在继续,但是其实从第15秒之后就没有请求。
(2)查看机器资源,从图中可以得出,机器的CPU资源占用率很低,远未达到瓶颈。
根据线程死锁的现场,猜测此时是发生了线程死锁。
2、验证猜想
方法一:通过jstack命令查看线程情况。对线程代码进行分析,获取到哪行代码导致的死锁。
jstack pid > filename.log
将dump下来的文件下载到本地,通过deadlock进行查找:
把图中的Deadlock内容复制出来:
http-nio-8080-exec-9: - waiting to lock <0x00000000e6a31c68> - locked <0x00000000e6a31c88> http-nio-8080-exec-1: - waiting to lock <0x00000000e6a31c88> - locked <0x00000000e6a31c68>
由上可知:线程http-nio-8080-exec-9和http-nio-8080-exec-1死锁。
分别在日志中查找http-nio-8080-exec-9和http-nio-8080-exec-1,可以看到都是BLOCKED状态;同时可以将问题代码位置反馈给开发。
方法二:通过jvisualvm查看
首先是调整远程监控的参数:
JAVA_OPTS="-Xms650m -Xmx650m -XX:+HeapDumpOnOutOfMemoryError -Dcom.sun.management.jmxremote.port=10086 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.0.110"
其中-Djava.rmi.server.hostname:远程连接地址,即程序所在机器地址
jvisualvm连接后如下:
上图中明显警告检测到了死锁,从图中线条的颜色也能看出来死锁的线程。
此时点击右上角“线程dump”,dump成功后如下,分析方法与jstack结果分许一致。