首先新建一个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")
public List<Long> loop() {
String data = "{\"data\":[{\"partnerid\":]";
return getPartneridsFromJson(data);
}
public static List<Long> getPartneridsFromJson(String data){
List<Long> list = new ArrayList<Long>(2);
if(data == 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.txt
top -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里面的方法造成的。
再测试死锁,先把上一个项目进程关掉,执行命令 kill -9 5700
,再重新运行项目
打开 http://192.168.0.8:8080/deadlock
在执行命令,用jstack打印出进程的线程堆栈信息,如重启项目后的进程号是8208,jstack 8208 > 8208.txt
查看 8208.txt cat 8208.txt
可以看到,文件里面已经找到了一处死锁