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();  
        }         
    }  
}

相关文章
|
6月前
|
Unix Shell Linux
5-15|Docker报错OCI runtime exec failed: exec failed: unable to start container process: exec: “/bin/ba
5-15|Docker报错OCI runtime exec failed: exec failed: unable to start container process: exec: “/bin/ba
|
9月前
|
Unix Docker 容器
使用docker 启动naocs 报错出现:standard_init_linux.go:241: exec user process caused "exec format error"
```markdown Error in Docker container startup: &quot;standard_init_linux.go:241: exec user process caused \&quot;exec format error\&quot;&quot;. Occurred at 2024-06-29 09:26:19.910, followed by a failed hook with a syslog delivery error at 09:27:20.193. Seeking solutions from experts. ```
|
9月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
Gaussian Process
【6月更文挑战第14天】
90 4
|
10月前
|
Java 应用服务中间件
完美解决tomcat启动异常:Invalid byte tag in constant pool: 19;Unable to process Jar entry [module-info.class]
完美解决tomcat启动异常:Invalid byte tag in constant pool: 19;Unable to process Jar entry [module-info.class]
1488 0
|
Java
Java Virtual Machine Process Status Tool <jps>
jps(Java Virtual Machine Process Status Tool)是java提供的一个显示当前所有java进程pid的命令
128 0
|
Shell C++
C++中的exec()函数
exec()函数在C++中是一个进程控制函数,用于创建新进程执行其他程序或命令行指令。exec()函数可以替换当前进程的代码和数据,创建新的进程运行其他程序。exec()函数有多个版本,例如execl、execv、execle、execve等,根据不同的参数类型和个数来使用。
218 0
|
NoSQL MongoDB 数据安全/隐私保护
OCI runtime exec failed: exec failed: unable to start container process: exec: "mongo": executable file not found in $PATH: unknown
OCI runtime exec failed: exec failed: unable to start container process: exec: "mongo": executable file not found in $PATH: unknown
1203 0
OCI runtime exec failed: exec failed: unable to start container process: exec: "mongo": executable file not found in $PATH: unknown
|
Ubuntu Linux 应用服务中间件
OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "ip": executable file not found in $PATH: unknown (Docker容器没有ip addr命令:exec ip addr 报错)
OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "ip": executable file not found in $PATH: unknown (Docker容器没有ip addr命令:exec ip addr 报错)
3873 0
|
测试技术
The concurrent snapshot for publication 'xxx' is not available because it has not been fully generated or the Log Reader Agent is not running to activ
在两台测试服务器部署了复制(发布订阅)后,发现订阅的表一直没有同步过来。重新生成过snapshot ,也重新初始化过订阅,都不能同步数据,后面检查Distributor To Subscriber History, 发现有如下日志信息: The concurrent snapshot for pub...
1548 0
|
关系型数据库 Java MySQL