Runtime.exec方法之获取process id

简介: Runtime.exec方法之获取process id

​最近一直在研究Runtime.exec的使用,通过这个来运行脚本命令。

我想知道通过这个方法来调用的脚本命令运行之后的pid是多少,网上找了一遍,发现有个比较靠谱的方法,在这里记录一下。

通过jna调用动态链接库的方式来获取pid,需要在代码里面导入一个jna-4.1.0.jar,对应的maven如下:

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>4.1.0</version>
</dependency>

然后新建一个接口Kernel32,代码如下:

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface Kernel32 extends Library{
   
    public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    public long GetProcessId(Long hProcess);
}

调用的时候使用,获取的 pid 就是我们想要的pid :

long pid = -1;
Field field = null;
try {
   
    field = process.getClass().getDeclaredField("handle");
    field.setAccessible(true);
    pid = Kernel32.INSTANCE.GetProcessId((Long) field.get(process));
} catch (Exception ex) {
   
    ex.printStackTrace();
}

上面的程序只适用于 windows 系统,下面我们讲程序优化一下,来适应更多的系统(linux、aix):

long pid = -1;
Field field = null;
if (Platform.isWindows()) {
   
    try {
   
        field = process.getClass().getDeclaredField("handle");
        field.setAccessible(true);
        pid = Kernel32.INSTANCE.GetProcessId((Long) field.get(process));
    } catch (Exception ex) {
   
        ex.printStackTrace();
    }
} else if (Platform.isLinux() || Platform.isAIX()) {
   
    try {
   
        Class<?> clazz = Class.forName("java.lang.UNIXProcess");
        field = clazz.getDeclaredField("pid");
        field.setAccessible(true);
        pid = (Integer) field.get(process);
    } catch (Throwable e) {
   
        e.printStackTrace();
    }
} else {
   
}

这样的话,可以获取linux程序的pid。

但是这里有个问题,就是如果通过脚本文件运行,即脚本文件写脚本启动命令,我们获取的pid是运行脚本窗口的命令行的pid,而非程序的真实pid,这点需要注意。在这里提供linux系统的另外解决办法。

就是通过优化启动脚本,我仿照了zookeper的启动脚本写了一个:

#!/bin/sh
JAVA_HOME=/home/jdk1.7
JAVA_OPTS=-Xmx512m
BASE_HOME=..
CONFIG_FILE=$BASE_HOME/conf/config.properties
PID_FILE=agent.pid

echo  -n "Starting agent ... "
if [ -f "$PID_FILE" ]; then
if kill -0 `cat "$PID_FILE"` > /dev/null 2>&1; then
 echo {
   mathJaxContainer[0]}PID_FILE"`.
 exit 0
fi
fi

nohup $JAVA_HOME/bin/java $JAVA_OPTS -Dlog4j.configuration=file:$BASE_HOME/conf/log4j.properties -cp "$BASE_HOME/conf:$BASE_HOME/lib/*" com.mysite.main.Application -f $CONFIG_FILE > /dev/null 2>&1 &

if [ $? -eq 0 ]
then
if /bin/echo -n $! > "$PID_FILE"
then
sleep 1
pid={
   mathJaxContainer[5]}{
   PID_FILE}")
if ps -p "${pid}" > /dev/null 2>&1; then
  echo STARTED 
  echo 'PID:'${pid}
else
  echo FAILED TO START
  exit 1
fi
else
echo FAILED TO WRITE PID
exit 1
fi
else
echo SERVER DID NOT START
exit 1
fi

通过阅读脚本大家可以看出,是在启动程序之后把pid记录到一个文件里面,通过对这个文件解析来获取真实pid,这个要求我们启动命令要后台执行(比如nohup),才能成功获取。这样写脚本还有效避免了重复启动程序的问题。

测试类

import com.sun.jna.Library;  
import com.sun.jna.Native;  

public interface Kernel32 extends Library {
     
    public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);  
    public long GetProcessId(Long hProcess);  
}
import java.lang.reflect.Field;  

public class Test1 {
     
    public static void main(String[] args) throws Exception {
     
        Runtime r = Runtime.getRuntime();  
        long pid = -1;  
        try {
     
            Process process = r.exec("D:\\Program Files\\Tencent\\QQ\\QQ.exe");  
            Field field = process.getClass().getDeclaredField("handle");  
            field.setAccessible(true);  
            pid = Kernel32.INSTANCE.GetProcessId((Long) field.get(process));  
            System.out.println(pid);  
        } catch (Exception ex) {
     
            ex.printStackTrace();  
        }         
    }  
}

相关文章
|
缓存 前端开发 Java
【二十八】springboot之通过threadLocal+参数解析器实现同session一样保存当前登录信息的功能
【二十八】springboot之通过threadLocal+参数解析器实现同session一样保存当前登录信息的功能
342 1
|
7月前
|
编解码 JavaScript 前端开发
Apipost自定义函数深度实战:灵活处理参数值秘籍
Apipost是一款强大的API调试工具,其自定义函数功能可直接在请求参数中处理数据,实时预览结果,提升效率与准确性。相比传统预执行脚本,该方法更直观、灵活,减少维护成本。内置多种函数如md5、sha256等,支持动态签名、中文转义、金融加密及电商库存测试等场景。同时,项目级自定义函数允许用户扩展JavaScript逻辑,满足复杂需求。通过三层架构(数据层、处理层、扩展层),Apipost实现参数处理智能化,助力高效开发与调试。
|
存储 开发工具 git
Git日常问题: 什么是LFS?及其错误解决办法
Git LFS(Git Large File Storage)是Git的一个扩展,用于管理大型文件,通过将大文件的实际内容存储在远程服务器上,而Git仓库中只保留一个轻量级的文本指针,从而加速仓库操作的速度并减小仓库大小。当遇到Git LFS相关错误时,通常需要安装Git LFS工具并按照官方文档进行配置。
1069 2
Git日常问题: 什么是LFS?及其错误解决办法
|
Linux
Linux 服务器下载百度网盘文件
本教程指导如何使用 `bypy` 库从百度网盘下载文件。首先通过 `pip install bypy` 安装库,接着运行 `bypy info` 获取登录链接并完成授权,最后将文件置于指定目录并通过 `bypy downdir /Ziya-13b-v1` 命令下载至本地。
1122 1
Linux 服务器下载百度网盘文件
|
机器学习/深度学习 运维 监控
智能运维在现代IT架构中的转型之路####
【10月更文挑战第29天】 本文旨在探讨智能运维(AIOps)如何成为现代IT架构不可或缺的一部分,通过分析其核心价值、关键技术及实践案例,揭示AIOps在提升系统稳定性、优化资源配置及加速故障响应中的关键作用。不同于传统运维模式的被动响应,智能运维强调预测性维护与自动化处理,为企业数字化转型提供强有力的技术支撑。 ####
281 0
|
移动开发 JSON Kubernetes
k8s异常诊断之no space left on device.
某用户反馈,特定节点一直拉不起来pod,提示no space left on device.,手动去docker run也是相同的报错 # docker run --name aestools-perf --cap-add CAP_SYS_ADMIN --privileged -ti --rm registry-vpc.cn-beijing.aliyuncs.com/my-nettools/aestools:onlyperf docker: Error response from daemon: error creating overlay mount to /var/li
3229 135
|
算法
【单目标优化算法】樽海鞘群算法(Matlab代码实现)
【单目标优化算法】樽海鞘群算法(Matlab代码实现)
412 0
|
Java 关系型数据库 数据库
基于SpringBoot大药房管理系统(程序+数据库+文档)
基于SpringBoot大药房管理系统(程序+数据库+文档)
|
前端开发 容器
|
资源调度 分布式计算 监控
YARN【工作机制】
YARN【工作机制】