使用Java的Runtime.exec()时如何添加超时值?
题
我有一个方法用于在本地主机上执行命令。我想在方法中添加一个超时参数,这样如果被调用的命令没有在合理的时间内完成,那么该方法将返回错误代码。这是迄今为止的样子,没有超时的能力:
public static int executeCommandLine(final String commandLine,
final boolean printOutput,
final boolean printError)
throws IOException, InterruptedException
{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(commandLine);
if (printOutput)
{
BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
System.out.println("Output: " + outputReader.readLine());
}
if (printError)
{
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Error: " + errorReader.readLine());
}
return process.waitFor();
}
有人能建议我实现超时参数的好方法吗?
解决方案
public static int executeCommandLine(final String commandLine,
final boolean printOutput,
final boolean printError,
final long timeout)
throws IOException, InterruptedException, TimeoutException {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(commandLine);
/* Set up process I/O. */
...
Worker worker = new Worker(process);
worker.start();
try {
worker.join(timeout);
if (worker.exit != null)
return worker.exit;
else
throw new TimeoutException();
} catch(InterruptedException ex) {
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
} finally {
process.destroyForcibly();
}
}
private static class Worker extends Thread {
private final Process process;
private Integer exit;
private Worker(Process process) {
this.process = process;
}
public void run() {
try {
exit = process.waitFor();
} catch (InterruptedException ignore) {
return;
}
}
}
其他提示
如果您使用的是Java 8或更高版本,则只需使用新的 waitFor with timeout :
Process p = ...
if(!p.waitFor(1, TimeUnit.MINUTES)) {
//timeout - kill the process.
p.destroy(); // consider using destroyForcibly instead
}
在 erickson的回答之后,我创建了一种更通用的方法来做同样的事情。
public class ProcessWithTimeout extends Thread
{
private Process m_process;
private int m_exitCode = Integer.MIN_VALUE;
public ProcessWithTimeout(Process p_process)
{
m_process = p_process;
}
public int waitForProcess(int p_timeoutMilliseconds)
{
this.start();
try
{
this.join(p_timeoutMilliseconds);
}
catch (InterruptedException e)
{
this.interrupt();
}
return m_exitCode;
}
@Override
public void run()
{
try
{
m_exitCode = m_process.waitFor();
}
catch (InterruptedException ignore)
{
// Do nothing
}
catch (Exception ex)
{
// Unexpected exception
}
}
}
现在,您所要做的就是如下:
Process process = Runtime.getRuntime().exec("<your command goes here>");
ProcessWithTimeout processWithTimeout = new ProcessWithTimeout(process);
int exitCode = processWithTimeout.waitForProcess(5000);
if (exitCode == Integer.MIN_VALUE)
{
// Timeout
}
else
{
// No timeout !
}
我使用详细的代码示例提供的三种方法实现了这一点(我是线程编程的新手,这些示例代码非常宝贵 - 如果它只是如此,我仍然会想到如何做到这一点用英文解释没有代码)。
我实现了我正在使用的实用程序类,使用三种方法来执行具有超时的命令,如下所示:
package com.abc.network.lifecycle.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Utility class for performing process related functions such as command line processing.
*/
public class ProcessUtility
{
static Log log = LogFactory.getLog(ProcessUtility.class);
/**
* Thread class to be used as a worker
*/
private static class Worker
extends Thread
{
private final Process process;
private Integer exitValue;
Worker(final Process process)
{
this.process = process;
}
public Integer getExitValue()
{
return exitValue;
}
@Override
public void run()
{
try
{
exitValue = process.waitFor();
}
catch (InterruptedException ignore)
{
return;
}
}
}
/**
* Executes a command.
*
* @param command
* @param printOutput
* @param printError
* @param timeOut
* @return
* @throws java.io.IOException
* @throws java.lang.InterruptedException
*/
public static int executeCommandWithExecutors(final String command,
final boolean printOutput,
final boolean printError,
final long timeOut)
{
// validate the system and command line and get a system-appropriate command line
String massagedCommand = validateSystemAndMassageCommand(command);
try
{
// create the process which will run the command
Runtime runtime = Runtime.getRuntime();
final Process process = runtime.exec(massagedCommand);
// consume and display the error and output streams
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", printOutput);
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", printError);
outputGobbler.start();
errorGobbler.start();
// create a Callable for the command's Process which can be called by an Executor
Callable<Integer> call = new Callable<Integer>()
{
public Integer call()
throws Exception
{
process.waitFor();
return process.exitValue();
}
};
// submit the command's call and get the result from a
Future<Integer> futureResultOfCall = Executors.newSingleThreadExecutor().submit(call);
try
{
int exitValue = futureResultOfCall.get(timeOut, TimeUnit.MILLISECONDS);
return exitValue;
}
catch (TimeoutException ex)
{
String errorMessage = "The command [" + command + "] timed out.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
catch (ExecutionException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an execution error.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
}
catch (InterruptedException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
catch (IOException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an IO error.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
}
/**
* Executes a command.
*
* @param command
* @param printOutput
* @param printError
* @param timeOut
* @return
* @throws java.io.IOException
* @throws java.lang.InterruptedException
*/
public static int executeCommandWithSleep(final String command,
final boolean printOutput,
final boolean printError,
final long timeOut)
{
// validate the system and command line and get a system-appropriate command line
String massagedCommand = validateSystemAndMassageCommand(command);
try
{
// create the process which will run the command
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(massagedCommand);
// consume and display the error and output streams
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", printOutput);
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", printError);
outputGobbler.start();
errorGobbler.start();
// run a thread which will set a flag once it has slept for the timeout period
final boolean[] flags = { true };
new Thread()
{
@Override
public void run()
{
try
{
Thread.sleep(timeOut);
}
catch (InterruptedException ex)
{
String errorMessage = "Timeout loop thread unexpectedly interrupted.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
flags[0] = false;
}
}.start();
// execute the command and wait
int returnValue = -1;
while (flags[0] && (returnValue < 0))
{
returnValue = process.waitFor();
}
// if the command timed out then log it
if (returnValue < 0)
{
log.warn("The command [" + command + "] did not complete before the timeout period expired (timeout: " +
timeOut + " ms)");
}
return returnValue;
}
catch (InterruptedException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
catch (IOException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an IO error.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
}
/**
* Executes a command.
*
* @param command
* @param printOutput
* @param printError
* @param timeOut
* @return
* @throws java.io.IOException
* @throws java.lang.InterruptedException
*/
public static int executeCommandWithWorker(final String command,
final boolean printOutput,
final boolean printError,
final long timeOut)
{
// validate the system and command line and get a system-appropriate command line
String massagedCommand = validateSystemAndMassageCommand(command);
try
{
// create the process which will run the command
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(massagedCommand);
// consume and display the error and output streams
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", printOutput);
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", printError);
outputGobbler.start();
errorGobbler.start();
// create and start a Worker thread which this thread will join for the timeout period
Worker worker = new Worker(process);
worker.start();
try
{
worker.join(timeOut);
Integer exitValue = worker.getExitValue();
if (exitValue != null)
{
// the worker thread completed within the timeout period
return exitValue;
}
// if we get this far then we never got an exit value from the worker thread as a result of a timeout
String errorMessage = "The command [" + command + "] timed out.";
log.error(errorMessage);
throw new RuntimeException(errorMessage);
}
catch (InterruptedException ex)
{
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
}
}
catch (InterruptedException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
catch (IOException ex)
{
String errorMessage = "The command [" + command + "] did not complete due to an IO error.";
log.error(errorMessage, ex);
throw new RuntimeException(errorMessage, ex);
}
}
/**
* Validates that the system is running a supported OS and returns a system-appropriate command line.
*
* @param originalCommand
* @return
*/
private static String validateSystemAndMassageCommand(final String originalCommand)
{
// make sure that we have a command
if (originalCommand.isEmpty() || (originalCommand.length() < 1))
{
String errorMessage = "Missing or empty command line parameter.";
log.error(errorMessage);
throw new RuntimeException(errorMessage);
}
// make sure that we are running on a supported system, and if so set the command line appropriately
String massagedCommand;
String osName = System.getProperty("os.name");
if (osName.equals("Windows XP"))
{
massagedCommand = "cmd.exe /C " + originalCommand;
}
else if (osName.equals("Solaris") || osName.equals("SunOS") || osName.equals("Linux"))
{
massagedCommand = originalCommand;
}
else
{
String errorMessage = "Unable to run on this system which is not Solaris, Linux, or Windows XP (actual OS type: \'" +
osName + "\').";
log.error(errorMessage);
throw new RuntimeException(errorMessage);
}
return massagedCommand;
}
}
我创建了一个类来使用和显示命令的输出和错误流(取自 http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4 ):
package com.abc.network.lifecycle.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Utility thread class which consumes and displays stream input.
*
* Original code taken from http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
*/
class StreamGobbler
extends Thread
{
static private Log log = LogFactory.getLog(StreamGobbler.class);
private InputStream inputStream;
private String streamType;
private boolean displayStreamOutput;
/**
* Constructor.
*
* @param inputStream the InputStream to be consumed
* @param streamType the stream type (should be OUTPUT or ERROR)
* @param displayStreamOutput whether or not to display the output of the stream being consumed
*/
StreamGobbler(final InputStream inputStream,
final String streamType,
final boolean displayStreamOutput)
{
this.inputStream = inputStream;
this.streamType = streamType;
this.displayStreamOutput = displayStreamOutput;
}
/**
* Consumes the output from the input stream and displays the lines consumed if configured to do so.
*/
@Override
public void run()
{
try
{
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = null;
while ((line = bufferedReader.readLine()) != null)
{
if (displayStreamOutput)
{
System.out.println(streamType + ">" + line);
}
}
}
catch (IOException ex)
{
log.error("Failed to successfully consume and display the input stream of type " + streamType + ".", ex);
ex.printStackTrace();
}
}
}
我创建了一个测试命令,大约需要10秒才能完成:
#!/bin/bash
sleep 10
echo 'TEST COMMAND RAN OK'
然后我创建了一个测试程序来测试三种不同的方法,每次调用超时值为5秒(命令应该失败)并且超时值为15秒(命令应该成功):
package com.abc.network.lifecycle.util;
public class ProcessUtilityTester
{
/**
* @param args
*/
public static void main(final String[] args)
{
try
{
String command = args[0];
int exitValue = -1;
System.out.println("\n\n5000ms timeout With Executors:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithExecutors(command, true, true, 5000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n5000ms timeout With Sleep:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithSleep(command, true, true, 5000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n5000ms timeout With Worker:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithWorker(command, true, true, 5000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n15000ms timeout With Executors:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithExecutors(command, true, true, 15000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n15000ms timeout With Sleep:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithSleep(command, true, true, 15000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
System.out.println("\n\n15000ms timeout With Worker:");
try
{
exitValue = -1;
exitValue = ProcessUtility.executeCommandWithWorker(command, true, true, 15000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("\nExit value:" + exitValue);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
System.exit(0);
}
}
}
这是我在运行测试程序时看到的内容:
5000ms timeout With Executors:
May 1, 2009 1:55:19 AM com.abc.network.lifecycle.util.ProcessUtility executeCommandWithExecutors
SEVERE: The command [/tmp/testcmd.sh] timed out.
java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:228)
at java.util.concurrent.FutureTask.get(FutureTask.java:91)
at com.abc.network.lifecycle.util.ProcessUtility.executeCommandWithExecutors(ProcessUtility.java:179)
at com.abc.network.lifecycle.util.ProcessUtilityTester.main(ProcessUtilityTester.java:19)
java.lang.RuntimeException: The command [/tmp/testcmd.sh] timed out.
at com.abc.network.lifecycle.util.ProcessUtility.executeCommandWithExecutors(ProcessUtility.java:186)
at com.abc.network.lifecycle.util.ProcessUtilityTester.main(ProcessUtilityTester.java:19)
Caused by: java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:228)
at java.util.concurrent.FutureTask.get(FutureTask.java:91)
at com.abc.network.lifecycle.util.ProcessUtility.executeCommandWithExecutors(ProcessUtility.java:179)
... 1 more
Exit value:-1
5000ms timeout With Sleep:
OUTPUT>TEST COMMAND RAN OK
OUTPUT>TEST COMMAND RAN OK
Exit value:0
5000ms timeout With Worker:
May 1, 2009 1:55:34 AM com.abc.network.lifecycle.util.ProcessUtility executeCommandWithWorker
SEVERE: The command [/tmp/testcmd.sh] timed out.
java.lang.RuntimeException: The command [/tmp/testcmd.sh] timed out.
at com.abc.network.lifecycle.util.ProcessUtility.executeCommandWithWorker(ProcessUtility.java:338)
at com.abc.network.lifecycle.util.ProcessUtilityTester.main(ProcessUtilityTester.java:47)
Exit value:-1
15000ms timeout With Executors:
OUTPUT>TEST COMMAND RAN OK
OUTPUT>TEST COMMAND RAN OK
Exit value:0
15000ms timeout With Sleep:
OUTPUT>TEST COMMAND RAN OK
Exit value:0
15000ms timeout With Worker:
OUTPUT>TEST COMMAND RAN OK
Exit value:0
因此,我可以告诉使用Worker线程类的方法效果最好,因为它在两种情况下都给出了预期的结果。使用Executors的方法也按预期工作,但需要注意的是它似乎在15000ms timout情况下运行命令两次(即我看到命令的输出两次)。使用sleep()方法的方法不会在5000ms超时情况下超出命令的超时,并显示输出两次,但在15000ms超时情况下按预期运行命令。
对于使用执行程序框架的每个人:您都忘记关闭执行程序。所以将其更改为以下内容:
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Future<Integer> ft = service.submit(call);
try {
int exitVal = ft.get(2000L, TimeUnit.MILLISECONDS);
return exitVal;
} catch (TimeoutException to) {
p.destroy();
throw to;
}
}
finally {
service.shutdown();
}
如果您不这样做,您的程序将保留一个活动的非守护程序线程,确保您的程序永远不会退出,直到您调用System.exit
对于那些不能使用新Java 8方法的人 waitFor(长时间超时,TimeUnit单位)
(因为它们在Android上或根本无法升级)你可以简单地从JDK源代码中删除它并将其添加到utils文件中的某个位置:
public boolean waitFor(long timeout, TimeUnit unit, final Process process)
throws InterruptedException
{
long startTime = System.nanoTime();
long rem = unit.toNanos(timeout);
do {
try {
process.exitValue();
return true;
} catch(IllegalThreadStateException ex) {
if (rem > 0)
Thread.sleep(
Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
}
rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
} while (rem > 0);
return false;
}
我从JDK8源代码中对原来的唯一更改是添加 Process
参数,以便我们可以调用 exitValue
方法。
exitValue
方法将直接尝试返回或抛出 IllegalThreadStateException
(如果进程尚未终止)。在这种情况下,我们等待收到的超时并终止。
该方法返回一个布尔值,因此如果返回false,则表示您需要手动终止该过程。
这种方式似乎比上面发布的任何内容都简单(期望直接调用waitFor肯定)。
适用于小型应用的轻量级解决方案:
public class Test {
public static void main(String[] args) throws java.io.IOException, InterruptedException {
Process process = new ProcessBuilder().command("sleep", "10").start();
int i=0;
boolean deadYet = false;
do {
Thread.sleep(1000);
try {
process.exitValue();
deadYet = true;
} catch (IllegalThreadStateException e) {
System.out.println("Not done yet...");
if (++i >= 5) throw new RuntimeException("timeout");
}
} while (!deadYet);
}
}
作为代理实施,如果超过您的阈值,则无法通话。
尝试在单独的线程或事件队列中使用Timer(或Sleep()),如果有可用的话。
有多种方法可以做到这一点,但我考虑使用Executor--它只是帮助你封装将线程中的退出值或异常传递回原始调用者。
final Process p = ...
Callable<Integer> call = new Callable<Integer>() {
public Integer call() throws Exception {
p.waitFor();
return p.exitValue();
}
};
Future<Integer> ft = Executors.newSingleThreadExecutor().submit(call);
try {
int exitVal = ft.get(2000L, TimeUnit.MILLISECONDS);
return exitVal;
} catch (TimeoutException to) {
p.destroy();
throw to;
}
我认为你不能绕过竞争条件,等待时间超时,然后在你调用destroy()之前终止进程。
我还测试了工作者的实现并且像魅力一样工作。在处理过程io下,我添加了线程来处理stde和stdo。如果工作线程超时我也退出io线程。
Process p = Runtime.getRuntime().exec(cmd.trim());
//setup error and output stream threads
CommandStreamThread eStream = new CommandStreamThread(p.getErrorStream(), "STDE");
CommandStreamThread oStream = new CommandStreamThread(p.getInputStream(), "STDO");
// kick them off
eStream.start();
oStream.start();
//setup a worker thread so we can time it out when we need
CommandWorkerThread worker=new CommandWorkerThread(p);
worker.start();
try {
worker.join(this.getTimeout());
if (worker.getExit() != null)
return worker.getExit();
else
throw new TimeoutException("Timeout reached:"+this.getTimeout()+" ms");
} catch(InterruptedException ex) {
eStream.interrupt();
oStream.interrupt();
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
} finally {
p.destroy();
}
首先是一些背景信息,我遇到了在运行命令时超时的问题,因为我尝试执行的程序永远不会打印出任何错误的调试或错误信息,并且会继续自行重试因为在重试时从未出现过错误或输出流,因此进程陷入困境。
所以在 process.exec()
或 process.start()
之后,
它将永远停留在这条线上,
BufferedReader input = new BufferedReader(newInputStreamReader(process.getInputStream()));
根据带有 public boolean waitFor(long timeout,TimeUnit unit)
方法的java 1.8,它应该具有“理想的”方法。在指定的超时后超时,但在我的情况下,它永远不会超时可能是因为我正在运行应用程序作为Windows服务(我已检查用户权限和帐户上的所有内容,但它没有帮助)。
所以我尝试使用下面的逻辑实现它,我们将继续使用 input.ready()
和一个超时标志来检查输入流。这个简单的解决方案就像一个魅力相比所有其他存在的。
代码:
public boolean runCommand() throws IOException, InterruptedException, Exception {
StringBuilder rawResponse = new StringBuilder();
System.out.println("Running Command " + Arrays.toString(command));
ProcessBuilder processBuilder = new ProcessBuilder(Arrays.asList(command));
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start(); //Executing the process
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
waitForTimeout(input, process); //Waiting for Timout
String line;
while ((line = input.readLine()) != null) {
rawResponse.append(line).append("\n");
}
return true;
}
//Timeout method
private void waitForTimeout(BufferedReader input, Process process) throws InterruptedException, Exception {
int timeout = 5;
while (timeout > 0) {
if (input.ready()) {
break;
} else {
timeout--;
Thread.sleep(1000);
if (timeout == 0 && !input.ready()) {
destroyProcess(process);
throw new Exception("Timeout in executing the command "+Arrays.toString(command));
}
}
}
}
你可以启动一个在你想要的时间内休眠的线程,并在睡眠后更改你在executeCommandLine方法中循环的布尔值。
类似的东西(没有经过测试或编译,这个解决方案是一个原型,你应该重构它,如果它适合你的需要):
public static int executeCommandLine(final String commandLine,
final boolean printOutput,
final boolean printError)
throws IOException, InterruptedException
{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(commandLine);
if (printOutput)
{
BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
System.out.println("Output: " + outputReader.readLine());
}
if (printError)
{
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Error: " + errorReader.readLine());
}
ret = -1;
final[] b = {true};
new Thread(){
public void run(){
Thread.sleep(2000); //to adapt
b[0] = false;
}
}.start();
while(b[0])
{
ret = process.waitFor();
}
return ret;
}
这是StreamThread
public class CommandStreamThread extends Thread{
private InputStream iStream;
private String cPrompt;
CommandStreamThread (InputStream is, String cPrompt)
{
this.iStream = is;
this.cPrompt = cPrompt;
}
public void run()
{
try
{
InputStreamReader streamReader= new InputStreamReader(this.iStream);
BufferedReader reader = new BufferedReader(streamReader);
String linesep=System.getProperty("line.separator");
String line=null;
while ((line=reader.readLine())!=null){
System.out.println(line);
//Process the next line seperately in case this is EOF is not preceded by EOL
int in;
char[] buffer=new char[linesep.length()];
while ( (in = reader.read(buffer)) != -1){
String bufferValue=String.valueOf(buffer, 0, in);
System.out.print(bufferValue);
if (bufferValue.equalsIgnoreCase(linesep))
break;
}
}
//Or the easy way out with commons utils!
//IOUtils.copy(this.iStream, System.out);
} catch (Exception e){
e.printStackTrace();
}
}
public InputStream getIStream() {
return iStream;
}
public void setIStream(InputStream stream) {
iStream = stream;
}
public String getCPrompt() {
return cPrompt;
}
public void setCPrompt(String prompt) {
cPrompt = prompt;
}
}
Apache Commons Exec可以帮助您做到这一点。
请参阅 http://commons.apache.org/proper/commons-exec /tutorial.html
String line = "your command line";
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
executor.setStreamHandler(streamHandler);
int exitValue = executor.execute(cmdLine);
System.out.println(exitValue);
System.out.println(outputStream.toString());
如果使用Java 8,我会选择Aleksander Blomsk&#248; ld回答,即p.waitFor(1,TimeUnit.MINUTE)
否则如果使用Java 6/7并使用Swing,则可以使用SwingWorker:
final Process process = ...
SwingWorker<Integer, Integer> sw = new SwingWorker<>() {
@Override
protected Integer doInBackground() throws Exception {
process.waitFor();
return process.exitValue();
}
};
sw.execute();
int exitValue = sw.get(1, TimeUnit.SECONDS);
if (exitValue == 0) {
//everything was fine
} else {
//process exited with issues
}
我知道这是一个很老的帖子;我需要一些类似项目的帮助,所以我想我可以提供一些我工作的代码和一些有用的代码。
long current = System.currentTimeMillis();
ProcessBuilder pb = new ProcessBuilder(arguments);
try{
pb.redirectErrorStream(true);
process = pb.start();
int c ;
while((c = process.getInputStream().read()) != -1 )
if(System.currentTimeMillis() - current < timeOutMilli)
result += (char)c;
else throw new Exception();
return result.trim();
}catch(Exception e){
e.printStackTrace();
}
return result;
希望这有助于未来:D