似乎您正在处理多线程问题,而不是获取进程的输出。
我刚刚制作了这个演示类,您可以使用:
CommandExecTest.java
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
public class CommandExecTest {
public static void main(String[] args) throws InterruptedException {
String executable = "cmd";
String[] commandParams = {"@ping -n 5 localhost","echo \"hello world\"","exit 123"};
boolean passCommandsAsLinesToShellExecutableAfterStartup = true;
AsyncExecutor asyncExecutor = new AsyncExecutor(executable, commandParams,passCommandsAsLinesToShellExecutableAfterStartup);
System.out.println("x"+"/x\tsecs in main thread \t\t status:"+asyncExecutor.runstate+" of async thread that monitors the process");
asyncExecutor.start();//start() invokes the run() method as a detached thread
for(int i=0;i<10;i++) {
// you can do whatever here and the other process is still running and printing its output inside detached thread
Thread.sleep(1000);
System.out.println(i+"/10\tsecs in main thread \t\t status:"+asyncExecutor.runstate+" of async thread that monitors the process");
}
asyncExecutor.join(); // main thread has nothing to do anymore, wait till other thread that monitor other process finishes as well
System.out.println("END OWN-PROGRAMM: 0 , END OTHER PROCESS:"+asyncExecutor.processExitcode);
System.exit(0);
}
}
运行状态
public static enum Runstate {
CREATED, RUNNING, STOPPED
}
AsyncExecutor.java
public static class AsyncExecutor extends Thread{
private String executable;
private String[] commandParams;
public ArrayList linesSoFarStdout = new ArrayList<>();
public ArrayList linesSoFarStderr = new ArrayList<>();
public Runstate runstate;
public int processExitcode=-1;
private boolean passCommandsAsLinesToShellExecutableAfterStartup = false;
public AsyncExecutor(String executable, String[] commandParams) {
this.executable=executable;
this.commandParams=commandParams;
this.runstate=Runstate.CREATED;
this.passCommandsAsLinesToShellExecutableAfterStartup=false;
}
/**
* if you want to run a single-process with arguments use false example executable="java" commandParams={"-jar","myjarfile.jar","arg0","arg1"}
*
* if you want to run a shell-process and enter commands afterwards use true example executable="cmd" commandParams={"@ping -n 5 localhost","echo \"hello world\"","exit 123"}
* @param executable
* @param commandParams
* @param passCommandsAsLinesToShellExecutableAfterStartup
*/
public AsyncExecutor(String executable, String[] commandParams, boolean passCommandsAsLinesToShellExecutableAfterStartup) {
this.executable=executable;
this.commandParams=commandParams;
this.runstate=Runstate.CREATED;
this.passCommandsAsLinesToShellExecutableAfterStartup=passCommandsAsLinesToShellExecutableAfterStartup;
}
@Override
public void run() {
this.runstate=Runstate.RUNNING;
// 1 start the process
Process p = null;
try {
if(passCommandsAsLinesToShellExecutableAfterStartup) {
// open a shell-like process like cmd and pass the arguments/command after opening it
// * example:
// * open 'cmd' (shell)
// * write 'echo "hello world"' and press enter
p = Runtime.getRuntime().exec(new String[] {executable});
PrintWriter stdin = new PrintWriter( p.getOutputStream());
for( int i = 0; i < commandParams.length; i++) {
String commandstring = commandParams[i];
stdin.println( commandstring);
}
stdin.close();
}
else {
// pass the arguments directly during startup to the process
// * example:
// * run 'java -jar myexecutable.jar arg0 arg1 ...'
String[] execWithArgs = new String[commandParams.length+1];
execWithArgs[0] = executable;
for(int i=1;i<=commandParams.length;i++) {
execWithArgs[i]=commandParams[i-1];
}
p = Runtime.getRuntime().exec( execWithArgs);
}
// 2 print the output
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader( new InputStreamReader( is));
InputStream eis = p.getErrorStream();
BufferedReader ebr = new BufferedReader( new InputStreamReader( eis));
String lineStdout=null;
String lineStderr=null;
while(p.isAlive()) {
Thread.yield(); // *
// * free cpu clock for other tasks on your PC! maybe even add thread.sleep(milliseconds) to free some more
// * everytime this thread gets cpu clock it will try the following codeblock inside the while and yield afterwards for the next time it gets cpu-time from sheduler
while( (lineStdout = br.readLine()) != null || (lineStderr = ebr.readLine()) != null) {
if(lineStdout!=null) {
System.out.println(lineStdout);
linesSoFarStdout.add(lineStdout);
}
if(lineStderr!=null) {
System.out.println(lineStderr);
linesSoFarStderr.add(lineStderr);
}
}
}
// 3 when process ends
this.processExitcode = p.exitValue();
}
catch(Exception e) {
System.err.println("Something went wrong!");
e.printStackTrace();
}
if(processExitcode!=0) {
System.err.println("The other process stopped with unexpected existcode: " + processExitcode);
}
this.runstate=Runstate.STOPPED;
}
}