写点什么

免费用鲲鹏资源!华为开发者空间实操:DevKit Java 性能分析,新手也能上手

  • 2025-09-11
    中国香港
  • 本文字数:5050 字

    阅读完需:约 17 分钟

免费用鲲鹏资源!华为开发者空间实操:DevKit Java 性能分析,新手也能上手

1 概述

1.1 背景介绍

鲲鹏 DevKit Java 性能分析工具是一款针对鲲鹏平台的性能分析和调优工具,Java 性能分析工具是针对基于鲲鹏的服务器上运行的 Java 程序的性能分析和优化工具,能图形化显示 Java 程序的堆、线程、锁、垃圾回收等信息,收集热点函数、定位程序瓶颈点,帮助用户采取针对性优。

1.2 适用对象

  • 企业

  • 个人开发者

  • 高校学生

1.3 案例时间

本案例总时长预计 40 分钟。

1.4 案例流程


说明:


① 自动部署鲲鹏服务器;② 安装鲲鹏 Devkit 插件;③ 配置在线分析环境,通过浏览器访问鲲鹏服务器,添加目标节点;④ 执行、编译死锁代码;⑤ 死锁在线分析;⑥ 修改代码,编译执行;⑦ 在线分析。

1.5 资源总览

本案例预计花费总计 0 元。

利用鲲鹏DevKit剖析Java死锁问题的性能分析👈👈👈👈完整版 案例体验请点这里进行查看。

2 操作步骤

2.1 自动部署鲲鹏服务器

在云主机桌面右键选择“Open Terminal Here”,打开命令终端窗口。



执行自动部署命令如下:


hcd deploy --password 远端服务器密码 --time 3600# --password    待部署项目所在ECS的root用户密码(至少8个字符)# --time value   待部署资源的保留期(单位为秒,至少600秒,默认600秒)。当前案例预估需要40分钟,可以配置time为1小时保留期。
复制代码


该命令会自动部署鲲鹏服务器。首次部署会直接执行,旧资源未到期时重复部署,会提示是否删除前面创建的资源,可以删除旧资源再次部署。



可以看到鲲鹏服务器链接:https://113.44.69.106:8084,表示部署成功,记录部署远端服务器公网IP,如截图中对应的就是:113.44.69.106



在开发者空间,我的开发资源下,找到鲲鹏沙箱环境,点击“使用详情”,可以看到我们刚刚自动部署的鲲鹏服务器,创建时间及资源释放时间等信息。


2.2 安装鲲鹏 Devkit 插件

云主机桌面单击鼠标右键,在菜单中选择“Open Terminal Here”打开终端。



通过 ssh 连接云服务器,如果有 yes/no 选择输入“yes”,然后输入 “云主机密码”,出现“Welcome to XXX”代表连接成功。


ssh root@云主机IP
复制代码



输入地址“wget https://kunpeng-repoXXX”下载鲲鹏DevKit压缩包:


wget https://kunpeng-repo.obs.cn-north-4.myhuaweicloud.com/Kunpeng%20DevKit/Kunpeng%20DevKit%2024.0.RC3/DevKit-All-24.0.RC3-Linux-Kunpeng.tar.gz
复制代码



稍作等待,下载完成执行“ls”可以看到下载的压缩包。



解压文件.


tar -zvxf DevKit-All-24.0.RC3-Linux-Kunpeng.tar.gz
复制代码



进入文件夹,可以看到“install.sh”,执行安装。


cd DevKit-All-24.0.RC3-Linux-Kunpengsudo ./install.sh
复制代码



如下图步骤,第一个默认回车即可。



出现如下图所示时选择“2”,去选择插件(1 是安装全部,如选错可以“ctrl + c”停止,重复上面 “sudo ./install.sh”指令即可)。



本案例只用到 java 性能分析,选择“6”,后面选项根据提示操作,多数默认回车即可,直至安装成功。



安装成功可以看到“https://192.168.2.191:8086”



执行命令,修改端口。


如下命令的第一个 ip 为 2.1 自动部署的鲲鹏服务器 IP,第二个 ip 为上图安装成功的 IP。


iptables -t nat -A PREROUTING -d XX.XX.XX.XX -p tcp --dport 8086 -j DNAT --to-destination XX.XX.XX.XX:8086
复制代码


2.3 配置在线分析环境

通过浏览器访问鲲鹏服务器,添加目标节点,以配置在线分析环境。


打开浏览器,输入“https://XX.XX.XX.XX:8086”(IP为2.1自动部署的鲲鹏服务器 IP),如果提示风险,点击接受并继续。



创建密码,并登录。



登录完成后添加目标环境:点击左上角“调优 添加”,在添加目标环境弹窗中输入:“用户名”,“云服务器密码”,点击“确定”;跳出来弹窗点击“确定”即可。


2.4 执行编译代码

云主机桌面单击鼠标右键,在菜单中选择“Open Terminal Here”打开终端。



通过 ssh 连接云服务器,如果有 yes/no 选择输入“yes”,然后输入 “云主机密码”,出现“Welcome to XXX”代表连接成功。


ssh root@云主机IP
复制代码


进入到云主机后,执行如下命令查看当前云主机的 JDK 安装情况。


java -version
复制代码



可以看到 JDK 默认是安装配置好的,输入“vim DeadLock.java”,回车进入,点击“i”进入编辑模式。


vim DeadLock.java
复制代码


DeadLock.java 代码地址,如跳转不了请输入以下地址复制代码:https://github.com/kunpengcompute/devkitdemo/blob/main/Hyper_tuner/testdemo/基于java性能分析工具的死锁调优实践/DeadLock.java


DeadLock.java 代码如下(因格式可能存在问题建议进入链接进行复制):


public class DeadLock {    private static final Integer lockOne = new Integer(1);    private static final Integer lockTwo = new Integer(2);      public static void main(String[] args){        new Thread(()->{            try{                System.out.println("thread1 is running");                synchronized (lockOne){                    System.out.println("thread1 get lock obj1");                    Thread.sleep(1000L);                    synchronized (lockTwo){                        System.out.println("thread12 get lock obj2");                        Thread.sleep(1000L);                    }                }            } catch(InterruptedException e){                e.printStackTrace();            }        }).start();        new Thread(()->{            try{                System.out.println("thread2 is running");                synchronized (lockTwo){                    System.out.println("thread2 get lock obj2");                    Thread.sleep(1000L);                    synchronized (lockOne){                        System.out.println("thread2 get lock obj1");                        Thread.sleep(1000L);                    }                }            } catch(InterruptedException e){                e.printStackTrace();            }        }).start();    }}
复制代码


代码复制完毕,键盘点击“esc”,然后输入“:wq”保存退出。



javac DeadLock.javajava DeadLock
复制代码


编译 java 文件,然后执行代码,可以看到执行成功。


2.5 死锁在线分析

进入浏览器界面,点击“调优”,点击“root@XXX”,点击 DeadLock 的“在线分析”。



对程序进行在线分析,在概览页签下观察每种状态的线程数,发现有两个线程处于阻塞状态,有死锁的嫌疑。



切换到 CPU 页签下的线程列表,找到阻塞状态的线程。观察一段时间发现发两个线程一直处于阻塞状态。



执行多次线程转储操作:在 CPU 下,点击“执行线程转储”,转储成功后点击“线程转储”下的锁分析图。发现两个阻塞中的线程发生了死锁。



选择 CPU 页签中线程转储下的原始数据,根据线程转储的原始数据得到死锁的相关信息。


点击优化建议的“查看详情”,查看死锁问题优化建议。



此时,我们已经获取到阻塞的原因及优化建议,点击“停止分析”。


2.6 修改代码,再次编译分析

找到阻塞的原因,接下来参考优化建议进行代码修改,解决死锁问题。


优化点解析说明:


  1. 共享变量的使用及操作


修改后的 DeadLock 类中定义了一个 volatile 修饰的共享变量 i,并且在每个线程获取锁成功并执行完同步代码块后,会对 i 进行自增操作(i++)。而修改前的 DeadLock 类中没有这样的共享变量及相关操作。


private static volatile Integer i = 1;
复制代码


原理说明:volatile 关键字保证可见性


volatile 关键字确保了共享变量 i 在多个线程之间的可见性。当一个线程修改了 i 的值,其他线程能够立即看到这个修改。这样,线程能够根据 i 的最新值来正确判断是否进入同步代码块获取锁,保证了整个机制的正确性。如果没有 volatile 关键字,线程可能会使用 i 的旧值,导致程序逻辑错误,无法有效避免死锁。


  1. 线程执行条件判断


在修改后的 DeadLock 类中,每个线程内部有一个 while(true)循环,并且根据共享变量 i 的奇偶性来决定是否获取锁。当 i 为奇数时,第一个线程尝试获取锁;当 i 为偶数时,第二个线程尝试获取锁。而修改前 DeadLock 类中,两个线程启动后直接尝试获取锁,没有基于共享变量的条件判断。


while(true){          if(i % 2 == 1){            synchronized (lockOne){              System.out.println("thread1 get lock obj1");              Thread.sleep(1000L);              synchronized (lockTwo){                  System.out.println("thread12 get lock obj2");                  Thread.sleep(1000L);                }            }            i++;          }        }while(true){          if(i % 2 == 0){            synchronized (lockOne){              System.out.println("thread1 get lock obj1");              Thread.sleep(1000L);              synchronized (lockTwo){                  System.out.println("thread12 get lock obj2");                  Thread.sleep(1000L);                }            }            i++;          }        }
复制代码


原理说明:打破循环等待条件


在修改前 DeadLock 中,线程 1 先获取 lockOne 锁,然后等待 lockTwo 锁;而线程 2 先获取 lockTwo 锁,然后等待 lockOne 锁,形成了循环等待,导致死锁。


在修改后 DeadLock 中,通过引入共享变量 i 和条件判断,使得两个线程不会同时去竞争 lockOne 和 lockTwo 锁。例如,当 i 为奇数时,只有线程 1 会去尝试获取 lockOne 锁,线程 2 此时不会竞争 lockOne 锁,从而打破了循环等待的条件。当线程 1 获取锁并执行完同步代码块后,i 变为偶数,此时线程 2 才有可能去获取 lockOne 锁,避免了死锁的发生。


回到终端,先停止程序:ctrl + z ,输入“vim DeadLock.java”,回车进入,点击“i”进入编辑模式。


vim DeadLock.java
复制代码


修改后代码如下:


public class DeadLock {    private static final Integer lockOne = new Integer(1);    private static final Integer lockTwo = new Integer(2);    private static volatile Integer i = 1;    public static void main(String[] args){        new Thread(()->{            try{                System.out.println("thread1 is running");        while(true){          if(i % 2 == 1){            synchronized (lockOne){              System.out.println("thread1 get lock obj1");              Thread.sleep(1000L);              synchronized (lockTwo){                  System.out.println("thread12 get lock obj2");                  Thread.sleep(1000L);                }            }            i++;          }        }            } catch(InterruptedException e){                e.printStackTrace();            }        }).start();        new Thread(()->{            try{                System.out.println("thread2 is running");        while(true){          if(i % 2 == 0){            synchronized (lockOne){              System.out.println("thread1 get lock obj1");              Thread.sleep(1000L);              synchronized (lockTwo){                  System.out.println("thread12 get lock obj2");                  Thread.sleep(1000L);                }            }            i++;          }        }            } catch(InterruptedException e){                e.printStackTrace();            }        }).start();    }}
复制代码


代码变动部分请参考下图,代码修改完毕后,键盘点击“esc”,然后输入“:wq”保存退出。



编译 java 文件,然后执行代码:


javac DeadLock.java  java DeadLock
复制代码


可以看到执行成功。运行效果如下:



回到浏览器,点击 DeadLock 的“在线分析”。



查看优化后程序,调整两个线程持有锁的顺序后,程序不再发生死锁。



可以看到建议中数量少了一条 CPU 死锁已经不存在,问题已被解决。点击“停止分析”,终端停止代码。



总结:Java 中的死锁问题一旦发生很难定位具体的代码位置,因为程序干扰因素比较多,所以涉及加锁解锁代码逻辑地方一定要仔细。建议如果涉及加锁的代码逻辑,程序是通过新起线程去执行或者是在线程池中执行,一定给线程设置有特定业务逻辑的名称,一旦发生问题也好定位。


在进行其他程序调优时,需要根据鲲鹏 DevKit Java 性能分析工具采集的实际结果和对应的优化建议进行调优操作。具体的调优思路可以参考本次实践。


至此,利用鲲鹏 DevKit 剖析 Java 死锁问题的性能分析实操全部结束。


用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

生于云,长于云,让开发者成为决定性力量

评论

发布
暂无评论
免费用鲲鹏资源!华为开发者空间实操:DevKit Java 性能分析,新手也能上手_鲲鹏 DevKit_华为云开发者联盟_InfoQ写作社区