首页 > 解决方案 > 从 Java 应用程序中而不是从命令行启动时系统命令挂起

问题描述

我有一个 Linux(Ubuntu 14.04.5 LTS)系统命令(一个可执行的 JAR 文件),如果从命令行手动启动,它会成功运行,但从 Java 应用程序(v1.8.0_191)中启动时会无限期挂起。

我没有编写可执行 JAR(它称为 Tabula,一个开源 PDF 解析器,但我认为系统命令的作用实际上与我的问题无关)。可执行 JAR 文件将 PDF 文件的路径作为其参数之一,并将 JSON 数据输出到标准输出。命令的平均完成时间通常只有几秒钟。

对于我处理的大多数 PDF 文件,没有问题,但对于一小部分 PDF,我编写的应用程序挂起。我发现问题是可执行的 JAR 命令没有返回,所以我的应用程序无限期地等待。如果我运行,ps -elf | grep java我可以看到命令仍在运行。偶尔,该进程会消耗非常少量的内存和CPU,但我不知道它在做什么。

但是,如果我自己在命令行上运行完全相同的可执行 JAR 命令,那么它会在几秒钟内完成并返回预期的输出。从表面上看,您会认为因为问题不是随机的并且仅限于特定的 PDF 输入文件,那么它一定是可执行 JAR 不喜欢的文件。如果这是真的,那么如果我从命令行手动运行该命令,为什么总是成功完成。

我已将相关代码提取为更小、更可测试的代码:

public static void main(String[] args) throws Exception {
    if (args.length != 1) {
        throw new Exception("Expected: folio ID as argument");
    }
    String folioID = args[0];

    String[] command = new String[] {
            "java", "-jar", Config.tabulaJARFile,
            "--stream",
            "--format", "JSON",
            "--pages", "all",
            String.format("%s/%s.pdf", Config.TABULA_INPUT_DIR, folioID)
    };

    System.out.println("Executing ==> " + String.join(" ", command));
    Process process = Runtime.getRuntime().exec(command);

    System.out.println("Waiting...");
    int exitCode = process.waitFor();

    if (exitCode != 0) {
        throw new Exception("Invalid exit code ["+exitCode+"]");
    }
    System.out.println("Retrieving input stream...");
    InputStream output = process.getInputStream();

    String jsonData = IOUtils.toString(output, "UTF-8");
    System.out.println(jsonData);

}

运行的示例输出为:

Executing ==> java -jar /home/ubuntu/tabula/tabula-1.0.3-jar-with-dependencies.jar --stream --format JSON --pages all /home/ubuntu/tabula/input/CK12345.pdf
Waiting...

...这将无限期挂起,但如果我自己在命令行上运行完全相同的命令,它将在几秒钟内完成。我也试过用 a 创建命令,ProcessBuilder但结果是一样的。为什么会发生这种情况?


似乎如果我使用ProcessBuildereg重定向进程的输出,processBuilder.redirectOutput(Redirect.INHERIT)则命令成功完成,但它将输出打印到控制台而不是让我在应用程序中捕获它。我通过将命令的输出重定向到文件来管理解决方法,然后读取文件的内容。

标签: java

解决方案


推荐阅读