• JVM之jstack的使用


    简介: 

      有些时候我们需要查看下jvm中的线程执行情况,比如,发现服务器的CPU的负载突然增高了、出现了死锁、死循环等,我们该如何分析呢?

    由于程序是正常运行的,没有任何的输出,从日志方面也看不出什么问题,所以就需要看下jvm的内部线程的执行情况,然后再进行分析查找出原因。

    这个时候,就需要借助于jstack命令了,jstack的作用是将正在运行的jvm的线程情况进行快照,并且打印出来;

    在Java中线程的状态一共被分成6种:

      初始状态:New,线程对象创建出来后,没有调用start方法,线程处于初始状态
      运行状态:包含了就绪状态和运行状态
        1.就绪状态:Ready,调用了Start方法,等待CPU分配资源
        2.运行状态:RUNNING,CPU分配资源给该线程,该线程处于运行状态
      阻塞状态 BLOCKED:
          线程获取资源,如果资源获取成功则正常运行,如果资源获取失败,就处于阻塞状态,等待什么时候获取到资源再变为运行状态
      等待状态 WAITING:线程手动调用了wait()方法,或者join()方法,这些方法都是主动进入等待状态,等待状态会将CPU资源让渡
          需要其他线程手动唤醒,notify(),notifyAll()唤起所有的等待线程
      超时等待状态 TIMED_WAITING:与等待状态相同,都是主动进入等待,也是需要其他线程唤醒,但是区别在与超时等待,如果超过了等待时间,则自动唤醒
          Thread.sleep(2000),在休眠等待时间内会将CPU资源让渡,然后等待时间结束自动进入运行状态
      终止状态 DIED:线程结束之后的状态

    案例:解决死锁问题

      如果在生产环境发生了死锁,我们将看到的是部署的程序没有任何反应了,这个时候我们可以借助jstack进行分析,下面我们实战下查找死锁的原因。

    构建死锁

      编写代码,启动2个线程,Thread1拿到了obj1锁,准备去拿obj2锁时,obj2已经被Thread2锁定,所以发送了死锁。

    public class LockTest {
        //定义资源
        private static Object obj1=new Object();
        private static Object obj2=new Object();
        //线程A:先获取到资源1,然后休眠2s,再获取资源2
        private static class ThreadA implements Runnable {
            @Override
            public void run() {
                synchronized (obj1) {
                    System.out.println("ThreadA获取到了OBJ1资源");
    
                    try {
                        //休眠2s,因为我们要将CPU资源让渡出去,这样线程B就可以先抢占obj2资源
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    synchronized (obj2) {
                        System.out.println("ThreadA获取到了OBJ2资源");
                    }
                }
            }
        }
        private static class ThreadB implements Runnable{
            @Override
            public void run() {
                synchronized (obj2){
                    System.out.println("ThreadB获取到了OBJ2资源");
    
                    try {
                        //休眠2s,因为我们要将CPU资源让渡出去,这样线程B就可以先抢占obj2资源
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    synchronized (obj1){
                        System.out.println("ThreadA获取到了OBJ1资源");
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            new Thread(new ThreadA()).start();
            new Thread(new ThreadB()).start();
        }
    }

      运行出现死锁问题

       检查状态

       查看线程运行情况

       主要看如下:

       在输出的信息中,已经看到,发现了1个死锁

      可以清晰的看到:

        Thread-1获取了 <0x0517c5b0> 的锁,等待获取 <0x0517c5a8>这个锁

        Thread-0获取了 <0x0517c5a8> 的锁,等待获取 <0x0517c5b0>这个锁

      由此可见,发生了死锁

  • 相关阅读:
    【转】VC 线程间通信的三种方式
    【转】MFC对话框和控件
    美国政府、部门构成及其运作
    贝叶斯推理(Bayes Reasoning)、独立与因式分解
    贝叶斯推理(Bayes Reasoning)、独立与因式分解
    机器学习:利用卷积神经网络实现图像风格迁移 (三)
    TBB、OpenCV混合编程
    VS编译环境中TBB配置和C++中lambda表达式
    概率图模型(PGM) —— 贝叶斯网络(Bayesian Network)
    概率图模型(PGM) —— 贝叶斯网络(Bayesian Network)
  • 原文地址:https://www.cnblogs.com/ws1149939228/p/12410416.html
Copyright © 2020-2023  润新知