死锁检测
# 查看Java PID(进程号)
[root@localhost ~]# jps -l
# 控制台输出线程的dump信息
[root@localhost tomcat]# jstack PID
[root@localhost tomcat]# jstack
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
# 可以查看线程是否被锁
-l long listing. Prints additional information about locks
-h or -help to print this help message
# 输出带有线程锁信息的线程信息
[root@localhost tomcat]# jstack -l 2439 >jstack2.log
# 输出线程信息
[root@localhost tomcat]# jstack 2439 >jstack.log
用对比工具对比上面jstack2.log和jstack.log文件:
死锁的代码
/**
* 死锁
* */
@RequestMapping("/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";
}
死循环检测
# 查看Java PID(进程号)
[root@localhost ~]# jps -l
# 控制台输出线程的dump信息
[root@localhost tomcat]# jstack -l PID
# top:找到占用CPU最大的进程号
[root@localhost tomcat]# top
# top -Hp 进程号:查看指定进程下的线程,选出占用毕竟高的线程进行分析
[root@localhost tomcat]# top -Hp 3063
top - 02:38:08 up 1:51, 2 users, load average: 2.47, 2.58, 2.97
Threads: 44 total, 2 running, 42 sleeping, 0 stopped, 0 zombie
%Cpu(s): 99.7 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1884124 total, 967372 free, 497876 used, 418876 buff/cache
KiB Swap: 1572860 total, 1572860 free, 0 used. 1201884 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3096 root 20 0 2562528 183620 14544 R 50.3 9.7 19:32.11 java
3097 root 20 0 2562528 183620 14544 R 49.7 9.7 5:56.43 java
3063 root 20 0 2562528 183620 14544 S 0.0 9.7 0:00.00 java
根据上面的分析,得出3063进程下的3096、3097线程占用CPU资源比较大,由于线程号都为十六进制,需要进行进制转换,转换如下:
十进制 十六进制
3096 0xc18
3097 0xc19
拿到转换后的十六进制,在线程dump中进行查找如下:
定位到程序代码,进行优化。
测试代码
/**
* 死循环
* */
@RequestMapping("/loop")
public List<Long> loop(){
String data = "{\"data\":[{\"partnerid\":]";
return getPartneridsFromJson(data);
}
public static List<Long> getPartneridsFromJson(String data){
//{\"data\":[{\"partnerid\":982,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":983,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":984,\"count\":\"10000\",\"cityid\":\"11\"}]}
//上面是正常的数据
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){
//partners = partners.substring(idpos+"partnerid".length());//1
continue;
}
String pid = partners.substring(colonpos+1,commapos);
if(pid == null || pid.length() <= 0){
//partners = partners.substring(idpos+"partnerid".length());//2
continue;
}
try{
list.add(Long.parseLong(pid));
}catch(Exception e){
//do nothing
}
partners = partners.substring(commapos);
}
return list;
}