J'ai une méthode que j'utilise pour exécuter une commande sur l'hôte local. J'aimerais ajouter un paramètre de délai d'attente à la méthode afin que, si la commande appelée ne se termine pas dans un délai raisonnable, la méthode retourne avec un code d'erreur. Voici à quoi cela ressemble jusqu'à présent, sans possibilité d'expiration du délai d'attente:
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();
}
Quelqu'un peut-il suggérer un bon moyen d'implémenter un paramètre de délai d'attente?
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;
}
}
}
Si vous utilisez Java 8 ou une version ultérieure, vous pouvez simplement utiliser le nouveau waitFor avec timeout :
Process p = ...
if(!p.waitFor(1, TimeUnit.MINUTES)) {
//timeout - kill the process.
p.destroy(); // consider using destroyForcibly instead
}
Suite à answer par erickson , j'ai créé un moyen plus générique de faire la même chose.
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
}
}
}
Maintenant, tout ce que vous avez à faire est comme suit:
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 !
}
J'ai implémenté cette méthode en utilisant les trois approches suggérées, accompagnées d'un exemple de code détaillé (je suis un novice avec la programmation de threads et ces exemples de codes sont d'une valeur inestimable - je me demanderais toujours comment procéder si cela venait d'être expliqué en anglais. sans code).
J'ai implémenté la classe utilitaire que j'utilise pour cela avec les trois méthodes permettant d'exécuter une commande avec un délai d'expiration similaire à celui-ci:
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;
}
}
J'ai créé une classe pour consommer et afficher les flux de sortie et d'erreur d'une commande (tirée de 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();
}
}
}
J'ai créé une commande de test qui prend environ 10 secondes:
#!/bin/bash
sleep 10
echo 'TEST COMMAND RAN OK'
Ensuite, j'ai créé un programme de test pour tester les trois méthodes différentes, appelant chacune avec une valeur de délai d'expiration de 5 secondes (la commande devait échouer) et avec une valeur de délai d'expiration de 15 secondes (la commande devait réussir):
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);
}
}
}
Voici ce que je vois quand je lance le programme de test:
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
Donc, d'après ce que je peux dire, l'approche utilisant une classe de thread Worker fonctionne le mieux, en ce sens qu'elle donne les résultats attendus dans les deux cas. L’approche utilisant Executors fonctionne aussi bien que prévu, avec l’avertissement qu'il semble exécuter la commande deux fois dans le cas du délai d’exécution de 15 000 ms (c’est-à-dire que la sortie de la commande est affichée deux fois). L'approche utilisant la méthode sleep () n'expulse pas la commande comme prévu dans le cas du délai d'expiration de 5 000 ms et affiche la sortie deux fois, mais exécute la commande comme prévu dans le cas du délai d'expiration de 15 000 ms.
Pour tous ceux qui utilisent le framework d’exécuteur: vous oubliez tous d’arrêter l’exécuteur. Alors changez-le comme suit:
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();
}
Si vous ne le faites pas, votre programme conservera un thread actif non démon, vous assurant ainsi que votre programme ne se terminera jamais tant que vous n'avez pas appelé System.exit
Pour ceux qui ne peuvent pas utiliser la nouvelle méthode Java 8 waitFor(long timeout, TimeUnit unit)
(car ils sont sous Android ou ne peuvent tout simplement pas être mis à niveau), vous pouvez simplement l'extraire du code source du JDK et l'ajouter quelque part dans votre fichier 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;
}
Le seul changement que j'ai apporté au code original à partir du code source JDK8 est l'ajout du paramètre Process
afin que nous puissions appeler la méthode exitValue
à partir du processus.
La méthode exitValue
essaiera directement de renvoyer ou de lancer une IllegalThreadStateException
si le processus n'est pas encore terminé. Dans ce cas, nous attendons le délai d'attente et nous terminons.
La méthode renvoie un booléen, donc si elle renvoie false, vous savez que vous devez arrêter manuellement le processus.
Cela semble plus simple que tout ce qui a été posté ci-dessus (attendez-vous à l’appel direct à waitFor, à coup sûr).
Une solution légère pour les petites applications:
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);
}
}
Implémentez en tant que délégué et échouez à l'appel s'il faut plus que votre seuil pour terminer.
Essayez d’utiliser un minuteur (ou Sleep ()), dans un thread séparé ou dans votre file d’événements, si vous en avez un.
J'ai également testé l'implémentation de l'ouvrier et fonctionne à merveille. Dans le processus de traitement io, j'ai ajouté des threads pour gérer stde et stdo. Si le thread de travail expire, je quitte également les threads 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();
}
Il y a différentes façons de le faire, mais j'aimerais utiliser un exécuteur - cela vous aide simplement à encapsuler la transmission de la valeur de sortie ou de l'exception du thread à l'appelant d'origine.
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;
}
Je pense que vous ne pouvez pas contourner la condition de concurrence critique selon laquelle le délai d'attente est dépassé, puis le processus se termine juste avant d'appeler destroy ().
Je sais que c'est vraiment vieux post; J'avais besoin d'aide pour un projet similaire alors j'ai pensé que je pourrais donner une partie de mon code que j'ai travaillé et ceux qui fonctionnent.
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;
J'espère que cela aide l'avenir: D
Apache Commons Exec peut vous aider à le faire.
Voir 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());
Vous pouvez lancer un thread qui dort pendant le temps que vous souhaitez et après avoir dormi, en modifiant un booléen que vous bouclez dans votre méthode executeCommandLine.
Quelque chose comme ça (non testé ni compilé, cette solution est un prototype que vous devriez refactoriser si cela vous convient):
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;
}
Si j'utilise Java 8, Aleksander Blomskøld répond: p.waitFor (1, TimeUnit.MINUTE)
sinon, si vous utilisez Java 6/7 et que vous utilisez Swing, vous pouvez utiliser 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
}
et voici le 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;
}
}