持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
前言
本次运行的环境:
- JDK 1.8
- Windows 10系统
- CentOS 7.X
一、测试程序
程序示例
- 同时开启两个线程进行交替执行
/**
* Created by lilinchao
* Date 2022/10/4
* Description 启动两个线程同时运行
*/
public class Test05 {
public static void main(String[] args) {
new Thread(() -> {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 running");
}
},"t1").start();
new Thread(() -> {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2 running");
}
},"t2").start();
}
}
运行
打开CMD窗口(如果是CentOS系统,直接通过命令行运行即可)
(1)通过javac命令先将程序编译成class文件
javac Test05.java
(2)通过Java命令运行编译好的class文件
java Test05
运行结果
t1 running
t2 running
t2 running
t1 running
t2 running
............
二、查看进程线程的方法
2.1 windows
(1)通过任务管理器可以查看进程和线程数
也可以通过任务管理器直接杀死进程
(2)通过tasklist 查看进程
C:\Users\Leefs>tasklist | findstr java
java.exe 6432 Console 3 114,764 K
java.exe 10160 Console 3 24,016 K
findstr后面跟上查找关键字
缺陷:根据查询出来的java.exe名称不能判断出来具体运行的Java进程,可以使用jps命令来查看具体的进程,后面将会详细介绍
(3)taskkill 杀死进程
C:\Users\Leefs>taskkill /F /PID 10160
成功: 已终止 PID 为 10160 的进程。
参数说明
/F:彻底杀死/PID:进程PID
2.2 Linux
(1)通过ps -ef命令查看Java进程
[root@admin ~]# ps -ef|grep java
root 1515 1463 4 22:58 pts/0 00:00:33 java Test05
root 2616 1488 0 23:10 pts/1 00:00:00 grep --color=auto java
grep后的参数为查找的进程名称
(2)通过top -H -p <PID> 查看某个进程(PID)的所有线程
[root@admin ~]# top -H -p 1515
- -H:指定显示线程的信息
- -p:指定具体的进程 id
显示内容如下:
- 但是同样的命令,有的执行结果可能是下面这种情况
COMMAND参数中显示的线程名称全都是java,看着是不是一脸懵,出现这种情况的原因是jdk线程名显示上的bug,如果使用 openjdk8 ,建议升级到222之后,这样可以通过top命令直接看到线程的名称。
关于这种情况如何查看线程信息,将会在下文进行详细介绍
(3)通过ps -fT -p <PID>查看某个进程(PID)的所有线程
[root@admin ~]# ps -fT -p 1515
显示如下信息
(4)通过kill杀死进程
[root@admin ~]# kill -9 1515
2.3 Java
(1)通过jps 命令查看所有 Java 进程
[root@admin ~]# jps
4602 Test05
4621 Jps
(2)通过jstack查看某个 Java 进程(PID)的所有线程状态
[root@admin ~]# jstack 4602
该命令只能查看Java线程执行过程中某一瞬间的状态信息,不能进行动态更新
(3)jconsole 查看某个 Java 进程中线程的运行情况(图形界面)
- CentOS系统,通过如下命令重新运行java类
java -Djava.rmi.server.hostname=`ip地址` -Dcom.sun.management.jmxremote -
Dcom.sun.management.jmxremote.port=`连接端口` -Dcom.sun.management.jmxremote.ssl=是否安全连接 -
Dcom.sun.management.jmxremote.authenticate=是否认证 java类
-
关闭防火墙,或者开放连接端口
-
Windows系统,使用快捷键
win+R打开运行窗口 -
在窗口中输入
jconsole并点击确定
- 进入到Java监视和管理控制台,选择远程进程输入
IP:连接端口号,点击连接
- 选择【线程】选项,可以动态查看线程连接信息
如果要认证访问,还需要做如下步骤
- 复制
jmxremote.password文件 - 修改
jmxremote.password和jmxremote.access文件的权限为 600 即文件所有者可读写 - 连接时填入
controlRole(用户名),R&D(密码)
三、通过jstack查看线程信息
本小节内容主要是针对jdk线程名显示上的bug,造成top命令无法查看到线程具体名称的问题
(1)执行top命令,查看所有java线程信息
top -H -p `pidof java`
(2)通过jstack 命令来打印一份堆栈信息
jstack -l `pidof java` > ./dble_jstack.log
有了上述导出结果,就可以看某个线程号在应用中具体对应哪个线程。
(3)将要查看的线程号转为16进制的数字
[root@admin ~]# printf "%x\n" 6837
1ab5
(4)在 jstack 的结果中查找线程的名字
[root@admin ~]# cat ./dble_jstack.log | grep "nid=0x1ab5"
"t2" #10 prio=5 os_prio=0 tid=0x00007f8340172800 nid=0x1ab5 waiting on condition [0x00007f832d78b000]
如果还需要更多的上下文信息,可以查看 grep 手册找响应的参数比如-A还有-B,甚至可以打开文件查找。