【问题标题】:Java threading question - listening to n error streamsJava线程问题——监听n个错误流
【发布时间】:2009-08-05 21:04:14
【问题描述】:

首先让我说,我在线程方面的经验非常低。

我有一个应用程序可以通过Runtime.exec 方法启动其他几个Java jar。问题是启动的 jars 需要同时运行,但为了获得启动 jars 的错误流,您基本上必须有一个循环“坐下来听”,直到过程完成。

这就是我现在拥有的:

_processes.add( Runtime.getRuntime().exec( commandList.toArray( new String[ commandList.size() ] ) ) );
Thread thread = new Thread( new Runnable() {
    private final int _processNumber = _processes.size() - 1;
    public void run() {
        String streamData = _processNumber + " : ";
        streamData += "StdError [\r";
        BufferedReader bufferedReader =
                new BufferedReader( new InputStreamReader( _processes.get( _processNumber ).getErrorStream() ) );
        String line = null;
        try {
            while ( ( line = bufferedReader.readLine() ) != null ) {
                streamData += line + "\r";
            }
            bufferedReader.close();
            streamData += "]\r";
            LOG.error( streamData );
        }
        catch ( Exception exception ) {
            LOG.fatal( exception.getMessage() );
            exception.printStackTrace();
        }
    }
} );
thread.start();

谁能解释如何让“错误流侦听器线程”正常工作?

TIA

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    不要使用 Runtime.getRuntime().exec(),而是使用 Process 来启动外部进程。它会让你的生活变得更轻松。

    我的一个项目的示例代码:

        //Build command 
        List<String> commands = new ArrayList<String>();
        commands.add("my_application");
        commands.add("arg1");
        commands.add("arg2");
        log.debug("{}", commands);
    
        //Run command with arguments
        ProcessBuilder pb = new ProcessBuilder(commands);
        pb.directory(directory);
        pb.redirectErrorStream(true);
        Process process = pb.start();
    
        //Read output
        StringBuilder out = new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader
            (process.getInputStream()));
    
        //Only log unique lines (you might not need this)
        String line = null, previous = null;
        while ((line = br.readLine()) != null)
            if (!line.equals(previous)) {
                previous = line;
                out.append(line).append('\n');
                log.debug(line);
            }
    
        //Check result
        if (process.waitFor() == 0)
            return 0;
    
        //Abnormal termination: Log command parameters and output and throw ExecutionException
        log.error("{}", commands);
        log.error("\n{}", out.toString());
        throw new ExecutionException(new IllegalStateException("MyApplication exit code 1"));
    

    【讨论】:

    • 我认为衍生线程及其相应流的并发性是这里的问题。我在 ProcessBuilder 中(或者在所有 Java 中)看不到太多可以更好地处理进程的内容。上面列出的文章中提到了 jconfig,但显然该项目已经死了(至少现在是这样)。
    • PipedOut/InputStream 在这里有什么帮助吗?
    【解决方案2】:

    有一个很好的教程here 关于如何使用 Runtime.exec()。通读所有内容,尤其是第 4 页,其中解释了如何使用在单独线程中运行的“StreamGobbler”来消耗正在执行的进程中的 std out 和 std err 流。

    基本上,您应该希望在伪代码中实现的是:

    Runtime rt1 = Runtime.getRuntime().exec("my command")
    new StreamGobbler(rt1.getOutputStream()).start()
    new StreamGobbler(rt1.getErrorStream()).start()
    //repeat for each external process (rt2, rt3 etc)
    ...
    rt1.waitFor()
    rt2.waitFor()
    rt3.waitFor()
    

    即您启动每个进程,并立即开始在单独的线程中使用每个进程的输出。随着消费线程的启动,只需等待每个进程完成并返回。

    【讨论】:

    • 是的,我以前读过这个。问题是 rt1 正在打开一个监听套接字,而 rt2 正在打开套接字的写入端。如果我启动 2 个线程来获取 rt1 的流,那么父线程似乎会阻塞并且 rt2 永远不会启动。我尝试运行所有 exec 命令,然后启动所有侦听器,当我这样做时,它会强制执行的命令阻塞。
    猜你喜欢
    • 1970-01-01
    • 2022-07-12
    • 1970-01-01
    • 2011-08-20
    • 2020-03-08
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    相关资源
    最近更新 更多