【JVM】Jstack实战死循环与死锁

死锁检测

# 查看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;  
	}  	
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

女汉纸一枚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值