首先新建一个springboot项目,新建一个controller
@RestController
public class DeadLockController {private Object lock1 = new Object();
private Object lock2 = new Object();
@GetMapping("/deadlock")
public String deadLock() {
new Thread(() -> {
synchronized (lock1) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
synchronized (lock2) {
System.out.println("Thread1 over");
}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
synchronized (lock1) {
System.out.println("Thread2 over");
}
}
}).start();
return "deadlock";
}@RequestMapping("/loop")
publicListloop() {
String data = "https://www.it610.com/article/{/"data\":[{\"partnerid\":]";
return getPartneridsFromJson(data);
}public static List getPartneridsFromJson(String data){
List list = new ArrayList(2);
if(data =https://www.it610.com/article/= null || data.length() <= 0){
return list;
}
int datapos = data.indexOf("data");
if(datapos < 0){
return list;
}
int leftBracket = data.indexOf("[",datapos);
int rightBracket= data.indexOf("]",datapos);
if(leftBracket < 0 || rightBracket < 0){
return list;
}
String partners = data.substring(leftBracket+1,rightBracket);
if(partners == null || partners.length() <= 0){
return list;
}
while(partners!=null && partners.length() > 0){
int idpos = partners.indexOf("partnerid");
if(idpos < 0){
break;
}
int colonpos = partners.indexOf(":",idpos);
int commapos = partners.indexOf(",",idpos);
if(colonpos < 0 || commapos < 0){
continue;
}
String pid = partners.substring(colonpos+1,commapos);
if(pid == null || pid.length() <= 0){
continue;
}
try{
list.add(Long.parseLong(pid));
}catch(Exception e){
}
partners = partners.substring(commapos);
}
return list;
}}
使用maven把项目打成jar包,然后使用命令:
nohup java -jar springboot-0.0.1-SNAPSHOT.jar &
运行项目先测试死循环,打开地址:http://192.168.0.8:8080/loop ,可以多开几个页面,然后使用top命令查看
文章图片
可以看到进程5700的cpu飙到快700, load average也一直在 不停上升。
使用命令:
jstack 5700 > 5700.txttop -p 5700 -H//查看5700进程的所有线程
文章图片
可以看到5732、5735、5729 等好几个线程cpu都飙到了99%,我们可以看一下 5700.txt中,这些线程在干什么 。以5732为例,由于5700.txt文本中的进程号都是16进制的,而5732是十进制,所以我们把5732转16进制得到1664。去5700.txt中查找1664,执行命令
grep -C 10 "1664" 5700.txt
文章图片
这样可以很清晰的看到是我们的DeadLockController里面的方法造成的。
【JVM: 使用 jstack 命令找出 cpu 飙高的原因】再测试死锁,先把上一个项目进程关掉,执行命令
kill -9 5700
,再重新运行项目打开 http://192.168.0.8:8080/deadlock
在执行命令,用jstack打印出进程的线程堆栈信息,如重启项目后的进程号是8208,
jstack 8208 > 8208.txt
查看 8208.txt
cat 8208.txt
文章图片
可以看到,文件里面已经找到了一处死锁
推荐阅读
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- jvm|JVM调优(线上 JVM GC 频繁耗时长,出现 LongGC 告警,这次排查后想说:还有谁(...))
- java内存区域与内存溢出异常
- JVM|JVM优化(一)
- 自动内存管理机制
- java|JVM之字节码如何在jvm流转
- jvm|从栈帧看字节码是如何在 JVM 中进行流转的
- java|[NIO和Netty] NIO和Netty系列(二): Java Reference详解
- 生活|jrebeleclipse/tomcat 使用方法