【问题标题】:Java run async processesJava 运行异步进程
【发布时间】:2018-06-22 03:22:35
【问题描述】:

我正在尝试运行异步进程,我不希望程序等到这些进程执行结束。我找到了这个问题how to run shell script asynchronously from within Java program,但它没有我正在寻找的答案。

我正在做的只是运行 bash 进程,并且在运行它之后,我不希望 Java 程序等到它完成。这就是我所做的:

public void runCommandLine(String directory) throws IOException {
    Thread commandLineThread = new Thread(() -> {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(
                    "/bin/bash");
            processBuilder.directory(new File(directory));
            Process process = processBuilder.start();
            try (OutputStreamWriter osw = new OutputStreamWriter(process.getOutputStream())) {
                osw.write(command);
            }
            printStream(process.getErrorStream(), true);
            printStream(process.getInputStream(), true);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    });
    commandLineThread.start();
    System.out.println("Task Dispatched");
}

我还在 main 方法的末尾放了另一个打印输出,所以我得到了这个输出:

Task Dispatched
Task Dispatched
End of psvm

但是程序不会终止,因为这两个进程还没有终止。

我该如何解决这个问题?

【问题讨论】:

    标签: java multithreading asynchronous process processbuilder


    【解决方案1】:

    您需要使您的线程成为守护线程。在启动之前使用setDaemon(true)

     commandLineThread.setDaemon(true);
    

    守护线程是不阻止 JVM 退出的线程。有关守护线程的更多信息,请参阅此问题:What is Daemon thread in Java?

    编辑:

    根据您的 cmets 判断,即使 JVM 即将退出,您也需要运行该命令。我假设command 变量包含您要运行的脚本?您可以进行两项更改以使程序按我认为的方式运行。

    1. 使用 -c 启动 bash 以执行您的命令,然后您不必将内容发送到输出流。
    2. 在启动等待输出的线程之前启动进程。

    生成的代码如下所示:

    public void runCommandLine(String directory) throws IOException {
        ProcessBuilder processBuilder = new ProcessBuilder(
                        "/bin/bash -c " + command);
        processBuilder.directory(new File(directory));
        Process process = processBuilder.start();
        Thread commandLineThread = new Thread(() -> {
            try {
                printStream(process.getErrorStream(), true);
                printStream(process.getInputStream(), true);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        });
        commandLineThread.setDaemon(true);
        commandLineThread.start();
        System.out.println("Task Dispatched");
    }
    

    【讨论】:

    • 好的,当我使用它时,程序终止但命令没有运行。也许它终止得太快而无法实际运行该进程?
    • 可能。尝试在主线程中启动命令,并且只在单独的线程中处理输出。
    • 我不太确定是什么问题,但是如果我将 printStreams 注释掉,那么它仍然不起作用,如果我将它们作为单独的线程运行并在它们上使用 setDaemon 它不起作用任何一个。我猜问题是 bash 没有足够的时间来实际运行它。我所做的是,我添加了 Thread.sleep() 2000 毫秒,现在它工作正常。我知道这听起来像是一种不好的做法,但我真的不知道如何解决这个问题......
    • @SarpKaya 检查我的编辑,看看这是否是你真正想要的。
    【解决方案2】:

    您正在读取进程的输出流,这就是您的 java 程序不退出的原因:

            printStream(process.getErrorStream(), true);
            printStream(process.getInputStream(), true);
    

    您的流式阅读将继续阻止您的代码。

    您可能希望将已启动进程的输出重定向到日志文件并稍后阅读。

    【讨论】:

    • 如果我把它注释掉,那么我可以看到它没有运行。
    • 不用注释掉,你可以
    【解决方案3】:
               Thread commandLineThread = new Thread(() -> {
                try {
                    BufferedReader br=new BufferedReader(
                            new InputStreamReader(
                                    process.getInputStream()));
                    String line;
    
                    while((line=br.readLine())!=null){
                        System.out.println(line);
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            });
            commandLineThread.setDaemon(true);
            commandLineThread.start();
    

    【讨论】:

      猜你喜欢
      • 2011-01-19
      • 2011-03-21
      • 2013-08-19
      • 2021-09-29
      • 2021-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-28
      相关资源
      最近更新 更多