海外vps云服务器免费用鲲鹏资源!华为开发者空间实操:DevKitJava性能分析

云峰服务器 1 概述 1.1 背景介绍 鲲鹏DevKit Java性能分析工具是一款针对鲲鹏平台的性能分析和调优工具,Java性能分析工具是针对基于鲲鹏的服务器上运行的Java程序的性能分···

云峰服务器

1 概述

1.1 背景介绍

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

1.2 适用对象

企业个人开发者高校学生

1.3 案例时间

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

1.4 案例流程

说明:

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

1.5 资源总览

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

资源名称

规格

单价(元)

时长(h)

鲲鹏沙箱资源

ECS/2核4GEIP/独享3M带宽EVS/通用型SSD 40G

免费

1

开发者空间-华为云- 云主机

2vCPUs | 4GB

免费

1

最新案例动态,请查阅《利用鲲鹏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代表连接成功。

复制

sshroot@云主机IP

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

复制

wgethttps://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-zvxfDevKit-All-24.0.RC3-Linux-Kunpeng.tar.gz

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

复制

cdDevKit-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-tnat-APREROUTING-dXX.XX.XX.XX-ptcp--dport8086-jDNAT--to-destinationXX.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代表连接成功。

复制

sshroot@云主机IP

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

复制

java-version

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

复制

云服务器都能干嘛

vimDeadLock.java

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

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

复制

publicclassDeadLock{privatestaticfinal Integer lockOne =newInteger(1);privatestaticfinal Integer lockTwo =newInteger(2);publicstaticvoidmain(String[] args){newThread(()->{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();newThread(()->{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保存退出。

复制

javacDeadLock.javajavaDeadLock

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

2.5 死锁在线分析

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

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

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

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

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

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

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

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

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

优化点解析说明:

共享变量的使用及操作

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

复制

privatestaticvolatileInteger i =1;

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

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

线程执行条件判断

在修改后的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进入编辑模式。

复制

vimDeadLock.java

修改后代码如下:

复制

publicclassDeadLock{privatestaticfinal Integer lockOne =newInteger(1);privatestaticfinal Integer lockTwo =newInteger(2);privatestaticvolatileInteger i =1;publicstaticvoidmain(String[] args){newThread(()->{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();newThread(()->{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文件,然后执行代码:

复制

javacDeadLock.javajavaDeadLock

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

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

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

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

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

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

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

云服务器地址是什么意思

您好:云优数据云计算 www.yunyoushuju.cn 2核2G6M最低19.9元/月 欢迎开机

发表评论

评论列表
未查询到任何数据!