【问题标题】:How to Exit a Process (.exec()) if the External Program hangs如果外部程序挂起,如何退出进程 (.exec())
【发布时间】:2013-01-07 03:35:33
【问题描述】:

让我解释一下我的软件。我的软件所做的只是创建 10 个线程并为每个线程分配一些任务。然后每个线程创建一个运行时进程,该进程将启动一个 cmd 批处理文件,该文件又将启动一个程序,该程序将远程登录到一个设备(我有大约 200 个)以轮询其配置。这是我的流程创建的代码:

Process p1 = java.lang.Runtime.getRuntime().exec("cmd /c  start /b /wait " + batchFile); 
int returnVal = p1.waitFor();

batchFile 是批处理文件的完整路径。不要误会我的意思,该软件在 100% 的执行情况下都可以正常工作,并且它只有一次在 95% 左右时挂起,所以我正在尝试寻找解决方案。为什么挂起不是我现在的问题,而是以后如何处理挂起..!

现在的问题是我需要等待进程完成,因为我的 telnet 客户端将写入一个文件,我稍后将在线程中读取该文件;因此使用 .waitFor() 。我的问题是如何让线程了解外部程序挂起?换句话说,我可以给外部程序一些时间限制来完成吗?如果没有,线程会杀死进程吗?

我还阅读了有关读取错误和输出流的信息;但是,我认为它不适用于这里,不是吗?

【问题讨论】:

  • “我也读过有关读取错误和输出流的信息;但是,我认为它不适用于这里,或者是吗?” 很可能是的。消费它们并显示它们。
  • TBH,我没有尝试过,因为我假设它们不会因为waitfor() 而使用。不会只调用一次吗?

标签: java process runtime.exec process-exit


【解决方案1】:

我还阅读了有关读取错误和输出流的信息;但是,我认为它不适用于这里,不是吗?

几乎可以肯定,它是适用的。尝试使用ProcessBuilder 而不是Runtime.exec 并在调用waitFor 之前读取所有输出。例如(省略了异常处理,特别是waitFor可能会在进程实际退出之前抛出InterruptedException

    ProcessBuilder pb = new ProcessBuilder(
        "cmd", "/c", "start", "/b", "/wait", batchFile);
    pb.redirectErrorStream(true);
    Process p = pb.start();
    IOUtils.closeQuietly(p.getOutputStream());
    IOUtils.copy(p.getInputStream(), System.out);
    // or alternatively throw away the output using
    // IOUtils.copy(p.getInputStream(), NullOutputStream.NULL_OUTPUT_STREAM);
    IOUtils.closeQuietly(p.getInputStream());
    int returnVal = p.waitFor();

(IOUtils 和 NullOutputStream 来自Apache commons-io)。

要回答标题中的实际问题,如果您的进程在正确读取其输出后仍然挂起,您可能需要使用p.destroy() 强制终止该进程。您可以定义一个类似的计时器任务

    public class TimeoutProcessKiller extends TimerTask {
      private Process p;
      public TimeoutProcessKiller(Process p) {
        this.p = p;
      }

      public void run() {
        p.destroy();
      }
    }

然后做

    // single shared timer instance
    Timer t = new Timer();

    // for each device
    Process p = pb.start();
    TimerTask killer = new TimeoutProcessKiller(p);
    t.schedule(killer, 30000);
    // ... read output stream as before ...
    int returnVal = p.waitFor();
    killer.cancel();

如果进程运行超过 30 秒,这将导致进程被杀死(调整 schedule 调用以更改超时)。

【讨论】:

  • 谢谢,这正是我想要在 Android 中避免 ANR(5 秒后)的方法,所以我改为 t.schedule(killer, 4500);
  • 在 Java 8 中,还可以使用 waitFor(long timeout, TimeUnit unit) 返回布尔值。 (Android 最低 API 26)
  • 我们真的必须调用 int returnVal = p.waitFor();在末尾?有人可以澄清我们是否使用过 t.schedule(killer, 30000);那么最后的 p.waitFor() 似乎是多余的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多