Java Runtime.exec()--是否可以将流输出与wait()/notify()同步?

Java Runtime.exec()--是否可以将流输出与wait()/notify()同步?,java,multithreading,process,stream,runtime,Java,Multithreading,Process,Stream,Runtime,我使用Runtime.exec()在Java中实现了一个简单的外部进程执行器。我已经实现了一个“streamgobbler”类,它使用来自进程的输出流和错误流的进程输出。我的代码使用process.waitFor()等待外部进程完成,然后打印进程返回代码 我所遇到的问题是,在“流GbBLBER”完成打印之前,该过程结束,因此在java输出(System .out)中,返回的退出代码出现在进程输出/错误行的中间。 我的问题是,是否可以使用wait()/notify()同步System.out上的输

我使用Runtime.exec()在Java中实现了一个简单的外部进程执行器。我已经实现了一个“streamgobbler”类,它使用来自进程的输出流和错误流的进程输出。我的代码使用process.waitFor()等待外部进程完成,然后打印进程返回代码

我所遇到的问题是,在“流GbBLBER”完成打印之前,该过程结束,因此在java输出(System .out)中,返回的退出代码出现在进程输出/错误行的中间。 我的问题是,是否可以使用wait()/notify()同步System.out上的输出,而不是在while循环中轮询每个StreamGoBler的活动状态

代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class RuntimeExecExample
{
    private enum StreamType
    {
        OUTPUT,
        ERROR
    }

    public class MyStreamGobbler extends Thread
    {
        private InputStream is;
        StreamType type;

        public MyStreamGobbler(InputStream is, StreamType type)
        {
            this.is = is;
            this.type = type;
        }

        public void run()
        {
            try
            {
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                String line=null;
                while ( (line = br.readLine()) != null)
                {
                    System.out.println(type.toString() + ">" + line);
                }
            } 
            catch (IOException ioe)
            {
                ioe.printStackTrace();
            }
        }
    }

    public void executeCommand(String args[])
    {
        try
        {
            Runtime rt = Runtime.getRuntime();

            String commandLine = "";
            for(String cmdItem : args)
            {
                commandLine += " " + cmdItem;
            }
            System.out.println("Exec-ing " + commandLine);

            Process proc = rt.exec(args);
            // any error message?
            MyStreamGobbler errorGobbler = new MyStreamGobbler(proc.getErrorStream(), StreamType.ERROR);
            // any output?
            MyStreamGobbler outputGobbler = new MyStreamGobbler(proc.getInputStream(), StreamType.OUTPUT);
            // kick them off
            errorGobbler.start();
            outputGobbler.start();
            // any error???
            int exitVal = proc.waitFor();

            /*
             * Wait for both to finish before printing exit value
             * IS THERE A WAY TO DO THIS WITH wait()/notify() ??
             */
            while(errorGobbler.isAlive())
                ;
            while(outputGobbler.isAlive())
                ;

            System.out.println("ExitValue: " + exitVal);
        }
        catch (Throwable t)
        {
            t.printStackTrace();
        }

    }

    public static void main(String args[])
    {

        if(args.length < 1)
        {
            System.out.println("USAGE: java RuntimeExecExample <cmd> [<arg1> <arg2> ..]");
            System.exit(1);
        }
        else
        {
            RuntimeExecExample runtimeExecExample = new RuntimeExecExample();
            runtimeExecExample.executeCommand(args);
        }
    }

}
导入java.io.BufferedReader;
导入java.io.IOException;
导入java.io.InputStream;
导入java.io.InputStreamReader;
公共类RuntimeExecExample
{
私有枚举流类型
{
产出,
错误
}
公共类MyStreamGobbler扩展线程
{
私有输入流是;
流线型;
public MyStreamGobbler(InputStream为,StreamType)
{
this.is=is;
this.type=type;
}
公开募捐
{
尝试
{
BufferedReader br=新的BufferedReader(新的InputStreamReader(is));
字符串行=null;
而((line=br.readLine())!=null)
{
System.out.println(type.toString()+“>”+行);
}
} 
捕获(ioe异常ioe)
{
ioe.printStackTrace();
}
}
}
public void executeCommand(字符串参数[])
{
尝试
{
Runtime rt=Runtime.getRuntime();
字符串命令行=”;
用于(字符串cmdItem:args)
{
命令行+=“”+cmdItem;
}
System.out.println(“执行”+命令行);
进程进程=rt.exec(args);
//有错误信息吗?
MyStreamGobbler errorGobbler=新的MyStreamGobbler(proc.getErrorStream(),StreamType.ERROR);
//有输出吗?
MyStreamGobbler outputGobbler=新的MyStreamGobbler(proc.getInputStream(),StreamType.OUTPUT);
//把他们踢出去
errorGobbler.start();
outputGobbler.start();
//有错误吗???
int exitVal=proc.waitFor();
/*
*在打印退出值之前,请等待两者都完成
*有没有办法用wait()/notify()实现这一点??
*/
while(errorGobbler.isAlive())
;
while(outputGobbler.isAlive())
;
System.out.println(“ExitValue:+exitVal”);
}
捕获(可丢弃的t)
{
t、 printStackTrace();
}
}
公共静态void main(字符串参数[])
{
如果(参数长度<1)
{
println(“用法:java RuntimeExecExample[…]”;
系统出口(1);
}
其他的
{
RuntimeExecExample RuntimeExecExample=新的RuntimeExecExample();
runtimeExecExample.executeCommand(args);
}
}
}

首先,您应该在启动的任何线程上调用
join()

其次,
System.out
是缓冲的,这可能解释了这一点。在阅读内容之前,请尝试调用
System.out.flush()


了解这是否是缓冲问题的一种方法是临时将调用的进程更改为写入
System.err
,而不是
System.out
System.err
未被缓冲。

在主线程中,除了执行waitFor()子进程以完成外,还要执行errorGobbler.join()和outputGobbler.join(),这样就不需要while(xGobbler.isAlive()).

为什么不使用倒计时锁存器?为什么要在单独的线程中运行gobbler?@EvgeniyDorofeev:gobbler应该在单独的线程中运行。因此,我想到的第一个解决方法是在两个列表实例中收集输出(两个流),然后在外部进程结束时,将这两者和退出代码打印到System.out。这个解决方案似乎很极端,我想知道是否可以等待线程结束。我认为System.err也被缓冲了。请参阅系统src:setErr0(新打印流(新缓冲输出流(fdErr,128),true));你应该为此感到高兴。标准错误流不应该被缓冲。不过这很奇怪。我似乎回忆起SystemErr刷新要比SystemOut.System.err.println(“111111”)快得多;System.out.println(“2222222”);总是在Eclipse中打印222221111(在我的电脑上)。但从cmd行看,这可能是因为Eclipse注入了自己的
System.out
System.err
,所以它可以在控制台视图中显示输出。这就是我想要的。谢谢