不灭的火

革命尚未成功,同志仍须努力下载JDK17

作者:AlbertWen  添加时间:2025-06-01 22:05:44  修改时间:2025-06-02 06:46:00  分类:07.Java框架/系统  编辑

附:Java使用Commons Exec执行本地命令行

参考一:豆包版

下面为你展示如何使用 Java 的 commons-exec 库来执行命令行并在必要时强制终止它。下面是一个完整的示例代码:

import org.apache.commons.exec.*;

import java.io.IOException;

public class CommandExecutor {

    public static void main(String[] args) {
        CommandExecutor executor = new CommandExecutor();
        // 执行一个长时间运行的命令
        executor.executeCommand("ping -t 127.0.0.1");
    }

    public void executeCommand(String commandLine) {
        // 创建命令行对象
        CommandLine cmdLine = CommandLine.parse(commandLine);
        // 创建执行器
        DefaultExecutor executor = new DefaultExecutor();
        // 设置工作目录
        executor.setWorkingDirectory(new java.io.File(System.getProperty("user.dir")));

        // 创建一个超时控制
        ExecuteWatchdog watchdog = new ExecuteWatchdog(60000); // 设置超时时间为60秒
        executor.setWatchdog(watchdog);

        // 设置执行结果处理器
        ExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();

        try {
            // 异步执行命令
            executor.execute(cmdLine, resultHandler);

            // 主线程休眠10秒后尝试强制终止命令
            Thread.sleep(10000);

            // 检查命令是否还在运行
            if (!resultHandler.hasResult()) {
                System.out.println("命令仍在运行,准备强制终止...");
                // 使用watchdog强制终止命令
                watchdog.destroyProcess();
                System.out.println("命令已被强制终止");
            } else {
                System.out.println("命令已完成执行");
            }

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

        // 等待命令执行完成
        try {
            resultHandler.waitFor();
            int exitValue = resultHandler.getExitValue();
            System.out.println("命令执行完成,退出值: " + exitValue);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("等待命令执行完成时被中断");
        } catch (ExecuteException e) {
            System.out.println("命令执行异常,退出值: " + e.getExitValue());
        }
    }
}

在使用这段代码时,你需要先在项目里添加 Apache Commons Exec 库的依赖。要是你用的是 Maven 项目,就在 pom.xml 中添加以下依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-exec</artifactId>
    <version>1.3</version>
</dependency>

此代码具备以下功能:

  1. 能够异步执行外部命令。
  2. 可以设置命令的超时时间。
  3. 能在需要时强制终止命令的执行。
  4. 会处理命令执行完成后的结果以及可能出现的异常。

你可以根据自身需求对代码进行修改,比如调整超时时间、更改要执行的命令等。

参考二:DeepSeek版

在 Java 中使用 commons-exec 库强制杀死命令行进程,可以通过 ExecuteWatchdog 实现。以下是详细步骤和示例代码:

解决方案

  1. 添加依赖:在 pom.xml 中添加 commons-exec 依赖。

  2. 创建 ExecuteWatchdog:用于监控和强制终止进程。

  3. 主动触发终止:调用 watchdog.destroyProcess() 强制杀死进程。

示例代码

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.PumpStreamHandler;
import java.io.ByteArrayOutputStream;

public class ProcessKiller {
    public static void main(String[] args) throws Exception {
        // 1. 创建长时间运行的命令(示例:Windows 持续 ping)
        CommandLine cmd = CommandLine.parse("ping 127.0.0.1 -n 20"); // 执行约 20 秒

        // 2. 设置执行器
        DefaultExecutor executor = new DefaultExecutor();
        executor.setExitValue(0); // 设置成功退出码为 0
        
        // 3. 捕获输出(可选)
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        PumpStreamHandler streamHandler = new PumpStreamHandler(output);
        executor.setStreamHandler(streamHandler);

        // 4. 创建看门狗(设置超时时间)
        ExecuteWatchdog watchdog = new ExecuteWatchdog(2000); // 2秒超时
        executor.setWatchdog(watchdog);

        // 5. 在新线程中执行命令(避免阻塞主线程)
        Thread execThread = new Thread(() -> {
            try {
                executor.execute(cmd);
            } catch (ExecuteException e) {
                if (watchdog.killedProcess()) {
                    System.out.println("进程被强制终止!");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        execThread.start();

        // 6. 等待一段时间后强制终止
        Thread.sleep(5000); // 5秒后终止
        if (watchdog.isWatching()) {
            watchdog.destroyProcess(); // 强制杀死进程
            System.out.println("已发送终止信号");
        }

        // 7. 打印输出(可选)
        System.out.println("命令输出:\n" + output.toString());
    }
}

关键点说明

  1. ExecuteWatchdog

    • 通过 setWatchdog() 绑定到执行器。

    • destroyProcess() 方法强制终止进程(调用操作系统的 kill 命令)。

    • killedProcess() 检查进程是否被手动终止。

  2. 超时控制

    • 构造函数 ExecuteWatchdog(timeout) 设置自动超时(毫秒)。

    • 示例中手动调用 destroyProcess() 主动终止,比自动超时更灵活。

  3. 多线程执行

    • 命令在单独线程中执行,避免阻塞主线程。

    • 主线程通过 Thread.sleep() 模拟等待后终止。

  4. 跨平台支持

    • commons-exec 自动处理不同操作系统(Windows/Linux)的进程终止命令。

注意事项

  • 资源释放:确保在 finally 块中关闭 ByteArrayOutputStream(示例省略)。

  • 僵尸进程:强制终止可能导致子进程残留,必要时需额外清理。

  • 错误处理:检查 ExecuteException 并处理超时或权限问题。

输出结果示例

已发送终止信号
进程被强制终止!
命令输出:
正在 Ping 127.0.0.1 具有 32 字节的数据...
来自 127.0.0.1 的回复: 字节=32 时间<1ms TTL=128
来自 127.0.0.1 的回复: 字节=32 时间<1ms TTL=128
...(部分输出)

通过此方案,你可以安全地强制终止由 commons-exec 启动的长时间运行或卡住的命令行进程。