【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;  
    }   

猜你喜欢

转载自blog.csdn.net/zlt995768025/article/details/81806617