从Java应用程序而非命令行启动时系统命令挂起

时间:2019-06-10 12:55:13

标签: 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...

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


看来,如果我使用ProcessBuilder重定向过程的输出,例如processBuilder.redirectOutput(Redirect.INHERIT)之后,命令成功完成,但是它将输出打印到控制台,而不是让我在应用程序中捕获它。我已经通过将命令的输出重定向到文件,然后读取文件的内容来解决此问题。

0 个答案:

没有答案
相关问题