Java并发编程中线程的运行

179 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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)通过任务管理器可以查看进程和线程数

03.并发编程之线程的运行01.jpg

也可以通过任务管理器直接杀死进程

(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

显示内容如下:

03.并发编程之线程的运行02.jpg

  • 但是同样的命令,有的执行结果可能是下面这种情况

03.并发编程之线程的运行03.jpg

COMMAND参数中显示的线程名称全都是java,看着是不是一脸懵,出现这种情况的原因是jdk线程名显示上的bug,如果使用 openjdk8 ,建议升级到222之后,这样可以通过top命令直接看到线程的名称。

关于这种情况如何查看线程信息,将会在下文进行详细介绍

(3)通过ps -fT -p <PID>查看某个进程(PID)的所有线程

[root@admin ~]# ps -fT -p 1515

显示如下信息

03.并发编程之线程的运行04.jpg

(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

03.并发编程之线程的运行05.jpg

该命令只能查看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类

03.并发编程之线程的运行06.jpg

  • 关闭防火墙,或者开放连接端口

  • Windows系统,使用快捷键win+R打开运行窗口

  • 在窗口中输入jconsole并点击确定

03.并发编程之线程的运行07.jpg

  • 进入到Java监视和管理控制台,选择远程进程输入IP:连接端口号,点击连接

03.并发编程之线程的运行08.jpg

  • 选择【线程】选项,可以动态查看线程连接信息

03.并发编程之线程的运行09.jpg

如果要认证访问,还需要做如下步骤

  • 复制 jmxremote.password 文件
  • 修改 jmxremote.passwordjmxremote.access 文件的权限为 600 即文件所有者可读写
  • 连接时填入 controlRole(用户名),R&D(密码)

三、通过jstack查看线程信息

本小节内容主要是针对jdk线程名显示上的bug,造成top命令无法查看到线程具体名称的问题

(1)执行top命令,查看所有java线程信息

top -H -p `pidof java`

03.并发编程之线程的运行10.jpg

(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,甚至可以打开文件查找。