java - Java耗时过长如何成功销毁进程?

标签 java timeout runtime processbuilder

我正在使用 Process 从我的 Java 程序中执行一个 shell 脚本,如果我的脚本需要很长时间,我想终止/销毁该进程。执行此操作的最佳方法是什么?

下面是我的代码:

public static void main(String[] args) throws IOException, InterruptedException {

    // Your script
    String script = "#!/bin/bash\n\necho \"Hello World\"\n\n readonly PARAM1=$param1\n echo $PARAM1\n\nreadonly PARAM2=$param2\n echo $PARAM2\n\n";

    // create a temp file and write your script to it
    File tempScript = File.createTempFile("temp_scripts_", "");
    tempScript.setExecutable(true);
    try (OutputStream output = new FileOutputStream(tempScript)) {
        output.write(script.getBytes());
    }

    // build the process object and start it
    List<String> commandList = new ArrayList<>();
    commandList.add(tempScript.getAbsolutePath());
    ProcessBuilder builder = new ProcessBuilder(commandList);
    builder.redirectErrorStream(true);
    builder.environment().put("param1", "abc");
    builder.environment().put("param2", "xyz");
    Process shell = builder.start();

    // read the output and show it
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(shell.getInputStream()))) {
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }

    // wait for the process to finish
    // but I want to kill/destroy the process if it takes too much time
    int exitCode = shell.waitFor();

    // delete your temp file
    tempScript.delete();

    // check the exit code (exit code = 0 usually means "executed ok")
    System.out.println("EXIT CODE: " + exitCode);
}

最佳答案

更新

Process 类没有带超时的“waitFor”方法,除非您使用的是 java 8。作为替代方案,您可以尝试启动一个等待进程完成的线程并使用 join(timeout) 加入这样的线程。

以下是您的代码的概念证明,经过修改以使用线程:

import java.io.*;
import java.util.*;

public class Test {

    public static void main(String[] args) throws IOException, InterruptedException {

        // Your script
        String script = getScriptFromSomewhere();

        // create a temp file and write your script to it
        File tempScript = File.createTempFile("temp_scripts_", "");
        tempScript.setExecutable(true);
        try (OutputStream output = new FileOutputStream(tempScript)) {
            output.write(script.getBytes());
        }

        // build the process object and start it
        List<String> commandList = new ArrayList<>();
        commandList.add(tempScript.getAbsolutePath());
        ProcessBuilder builder = new ProcessBuilder(commandList);
        builder.redirectErrorStream(true);
        builder.environment().put("param1", "abc");
        builder.environment().put("param2", "xyz");
        Process shell = builder.start();

        // Start the interrupting thread
        long timeoutMillis = 5000;
        ExecutingThread thread = new ExecutingThread(shell, timeoutMillis);
        thread.start();

        // read the output and show it
        byte[] buffer = new byte[1024];
        try (InputStream input = shell.getInputStream()) {
            int read;
            while ((read = input.read(buffer)) != -1) {
                String text = new String(buffer, 0, read);
                System.out.print(text);
            }
        }

        // wait for the process to finish (or be interrupted)
        thread.join();

        if(!thread.isFinished()) {

            System.out.println("PROCESS WAS INTERRUPTED");

        } else {

            // check the exit code (exit code = 0 usually means "executed ok")
            System.out.println("PROCESS FINISHED, EXIT CODE: " + thread.getExitValue());

        }


        // delete your temp file
        tempScript.delete();
    }
}

class ExecutingThread extends Thread {

    private long timeoutMillis;
    private WaitingThread waitingThread;

    public ExecutingThread(Process shell, long timeoutMillis) {
        this.timeoutMillis = timeoutMillis;
        this.waitingThread = new WaitingThread(shell);
    }

    @Override
    public void run() {
        waitingThread.start();
        try {
            waitingThread.join(timeoutMillis);
        } catch (InterruptedException ignore) {
        }
        if(waitingThread.isAlive()) {
            waitingThread.interrupt();
        }
    }

    public int getExitValue() {
        return waitingThread.getExitValue();
    }

    public boolean isFinished() {
        return waitingThread.isFinished();
    }

}


class WaitingThread extends Thread {

    private Process shell;
    private volatile int exitValue;
    private volatile boolean finished = false;

    public WaitingThread(Process shell) {
        this.shell = shell;
    }

    @Override
    public void run() {
        try {
            exitValue = shell.waitFor();
            finished = true;
        } catch (InterruptedException e) {
            shell.destroy();
        }
    }

    public int getExitValue() {
        return exitValue;
    }

    public boolean isFinished() {
        return finished;
    }

}

关于java - Java耗时过长如何成功销毁进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32747670/

相关文章:

java - 打印大型 Swing 组件

java - 从另一个 java 链码调用 java 链码

java - 这是打印二维数组最快的方法吗?

java - 在java中运行时递归地改变系统属性

java - 如何在运行时从 JTextArea 运行/编译 Java 代码?

java - Java 项目中的多个 .properties 文件

java - 线程 "main"java.io.FileNotFoundException : (The system cannot find the file specified) 中的异常

javascript - 了解 JavaScript 中的自动页面刷新

MySQL Workbench 在空闲时断开连接

c++ - QT与Arduino的串行通信超时