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

相关文章
|
3天前
|
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. ```
|
18天前
|
机器学习/深度学习 TensorFlow 算法框架/工具
Gaussian Process
【6月更文挑战第14天】
18 4
|
2月前
|
Java 数据库 索引
GreenDao,clearIdentityScope报错Error:Execution failed for task ':app:compileDebugJavaWithJavac'. > Com
GreenDao,clearIdentityScope报错Error:Execution failed for task ':app:compileDebugJavaWithJavac'. > Com
22 1
Cannot add task ‘wrapper‘ as a task with that name already exists.
Cannot add task ‘wrapper‘ as a task with that name already exists.
167 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
1010 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 报错)
3530 0
Runtime Errors - START_CALL_SICK
Runtime Errors - START_CALL_SICK
239 0
|
关系型数据库 Java MySQL