【问题标题】:Failure to start program from java (using ProcessBuilder)无法从 java 启动程序(使用 ProcessBuilder)
【发布时间】:2009-06-25 12:21:24
【问题描述】:

我正在尝试从 java 应用程序调用 cleartool,但即使是简单的“-version”参数,cleartool 也会挂起。运行 cleardiff 而不是 cleartool 可以正常工作,因此显然 cleartool 程序有一些特定的东西(我认为这与它的交互功能有关)。

下面的程序

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

public class ExecTesting extends Thread {

    private List<String> command = new ArrayList<String>();

    public ExecTesting (List<String> command) {
        super();
        this.command = command;
    }

    private void print(String s) {
        System.out.println(s);
    }

    @Override
    public void run() {
        Process process;
        OutputStream stdin;
        InputStream stdout;
        InputStream stderr;
        String line;

        try {
            String commandString = joinList(command, " ");
            print("Executing: " + commandString);

            // runtime.exec has several issues (http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1)
            // better to use ProcessBuilder (http://java.sun.com/developer/JDCTechTips/2005/tt0727.html#2)
            //process = Runtime.getRuntime().exec(commandString);
            process = new ProcessBuilder(command).start();
            // it fails in both cases though

            stdin  = process.getOutputStream();
            stdout = process.getInputStream();
            stderr = process.getErrorStream();

            BufferedReader bufferedStderr = new BufferedReader(new InputStreamReader(stderr));
            while ((line = bufferedStderr.readLine()) != null) {
                print("stderr: " + line);
            }
            bufferedStderr.close();

            BufferedReader bufferedStdout = new BufferedReader(new InputStreamReader(stdout));
            while ((line = bufferedStdout.readLine()) != null) {
                print("stdout: " + line);
            }
            bufferedStdout.close();

            stdin.close();
            stdout.close();
            stderr.close();

            process.waitFor();
            print("Execution finished, exit code " + process.exitValue());
            process.destroy();
        } catch (IOException e) {
            print("IOException: " +e.getStackTrace());
        } catch (InterruptedException e) {
            print("InterruptedException: " + e.getStackTrace());
        }

    }

    /* assumes a list with at least one element */
    private static String joinList(List<String> list, String glue) {
        Iterator<String> i = list.iterator();
        String ret = i.next();
        while (i.hasNext()) {
            ret += glue + i.next();
        }
        return ret;
    }

    public static void main(String[] args) {
        ArrayList<String> cmd1 = new ArrayList<String>();
        cmd1.add("c:\\Program Files\\Rational\\ClearCase\\bin\\cleardiff.exe");
        cmd1.add("-version");
        ExecTesting et1 = new ExecTesting(cmd1);
        et1.start();

        ArrayList<String> cmd2 = new ArrayList<String>();
        //cmd2.add("c:\\Program Files\\Rational\\ClearCase\\bin\\cleardiff.exe");
        cmd2.add("c:\\Program Files\\Rational\\ClearCase\\bin\\cleartool.exe");
        cmd2.add("-version");
        ExecTesting et2 = new ExecTesting(cmd2);
        et2.start();

        et1 = new ExecTesting(cmd1);
        et1.start();
    }
}

给出以下输出

Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
Executing: [c:\Program Files\Rational\ClearCase\bin\cleartool.exe, -version]
Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
stdout: cleardiff                         2003.06.10+ (Tue Jul 13 14:02:05  2004)
Execution finished, exit code 0

在 cleartool 命令的执行上挂起。如果改为将 cmd2 更改为 cleardiff,则输出符合预期

Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
stdout: cleardiff                         2003.06.10+ (Tue Jul 13 14:02:05  2004)
Execution finished, exit code 0
stdout: cleardiff                         2003.06.10+ (Tue Jul 13 14:02:05  2004)
Execution finished, exit code 0
stdout: cleardiff                         2003.06.10+ (Tue Jul 13 14:02:05  2004)
Execution finished, exit code 0

问题:有谁知道 cleartool 为何挂起以及如何解决?

【问题讨论】:

    标签: java exec


    【解决方案1】:

    您似乎在开始等待终止之前关闭了 I/O 流之前。您还可以按顺序阅读标准错误和标准输出。但是,读取到 stderr 会阻塞,因为应用程序没有打印错误,并且您不会进入读取 stdout 的阶段。这陷入僵局。

    你可以通过ProcessBuilder.redirectErrorStream()加入stderr和stdout,然后你只需要读取stdout。

    您的示例在某些情况下有效,因为当您在 stderr 上被阻塞时,stdout 上的应用程序响应不会达到通信缓冲区的大小。当应用程序退出时,stderr 循环退出并且 stdout 循环能够检索该缓冲区的内容。

    【讨论】:

      【解决方案2】:

      您应该在单独的线程中使用 stdout 和 stderr,否则您将遇到阻塞行为。

      我怀疑这就是在这种情况下发生的事情(并且它与 cleartool/cleardiff 无关,除了它们输出 stdout/err 之外)。请参阅this answer 了解更多信息。

      【讨论】:

        猜你喜欢
        • 2020-09-19
        • 2017-04-22
        • 1970-01-01
        • 2013-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多