Ich habe eine Methode, mit der ich einen Befehl auf dem lokalen Host ausführe. Ich möchte der Methode einen Timeout-Parameter hinzufügen, damit die Methode mit einem Fehlercode zurückgegeben wird, wenn der aufgerufene Befehl nicht in angemessener Zeit beendet wird. So sieht es bisher aus, ohne dass eine Zeitüberschreitung möglich ist:
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();
}
Kann mir jemand eine gute Möglichkeit vorschlagen, einen Timeout-Parameter zu implementieren?
Antworten:
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; } } }
quelle
Thread.join(long time)
oderThread.wait(long time)
, wasThread.join(long time)
nennen kann. Wie stoppt dies die Ausführung des Prozesses, wenn das Zeitlimit abgelaufen ist? Ich habe einen Test mit den oben genannten Methoden ausgeführt, bei dem ich die aktuelle Uhrzeit druckestdout
, den Prozess ausführe und dann die Uhrzeit erneut drucke. Die Ausführung des Prozesses dauert ungefähr 3 Sekunden. Der Vorgang wird immer nach Ablauf der Zeitüberschreitungsperiode abgeschlossen, obwohl ich die Zeitüberschreitung als 1s angegeben habe und eine a erwarteTimeoutException
.Process.destroy()
darauf, unvollendete Prozesse nach dem Timeout zu beenden . Ich werde einige Tests machen. Welches Betriebssystem verwenden Sie? Haben Sie Ihren Test in einer IDE oder in einer Shell ausgeführt?Wenn Sie Java 8 oder höher verwenden, können Sie einfach das neue waitFor mit Timeout verwenden :
Process p = ... if(!p.waitFor(1, TimeUnit.MINUTES)) { //timeout - kill the process. p.destroy(); // consider using destroyForcibly instead }
quelle
Nach der Antwort von erickson habe ich eine allgemeinere Methode entwickelt, um dasselbe zu tun.
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 } } }
Jetzt müssen Sie nur noch Folgendes tun:
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 ! }
quelle
waitForProcess
, um falsche Interrupts zu berücksichtigen ...: paste.ubuntu.com/9898052p_timeoutMilliseconds
zu lange wechseln . zBpublic int waitForProcess(long timeoutMilliseconds)
Ich habe dies mithilfe der drei vorgeschlagenen Ansätze implementiert, die mit einem detaillierten Codebeispiel geliefert wurden (ich bin ein Anfänger in der Thread-Programmierung und diese Beispielcodes waren von unschätzbarem Wert - ich würde mir immer noch den Kopf kratzen, wie dies zu tun ist, wenn es nur auf Englisch erklärt würde ohne Code).
Ich habe die Dienstprogrammklasse, die ich dafür verwende, mit den drei Methoden zum Ausführen eines Befehls mit einer Zeitüberschreitung wie folgt implementiert:
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; } }
Ich habe eine Klasse erstellt, um die Ausgabe- und Fehlerströme eines Befehls zu verwenden und anzuzeigen (entnommen aus 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(); } } }
Ich habe einen Testbefehl erstellt, der ungefähr 10 Sekunden dauert:
#!/bin/bash sleep 10 echo 'TEST COMMAND RAN OK'
Dann habe ich ein Testprogramm erstellt, um die drei verschiedenen Methoden zu testen, wobei jede mit einem Timeout-Wert von 5 Sekunden (Befehl sollte fehlschlagen) und einem Timeout-Wert von 15 Sekunden (Befehl sollte erfolgreich sein) aufgerufen wird:
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); } } }
Folgendes sehe ich, wenn ich das Testprogramm ausführe:
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
Soweit ich das beurteilen kann, funktioniert der Ansatz mit einer Worker-Thread-Klasse am besten, da er in beiden Fällen die erwarteten Ergebnisse liefert. Der Ansatz mit Executors funktioniert ebenfalls wie erwartet, mit der Einschränkung, dass der Befehl im Fall einer Zeitüberschreitung von 15000 ms anscheinend zweimal ausgeführt wird (dh ich sehe die Ausgabe für den Befehl zweimal). Bei der Verwendung der sleep () -Methode wird der Befehl nicht wie im Zeitlimit von 5000 ms erwartet zeitlich begrenzt und die Ausgabe zweimal angezeigt, sondern der Befehl wird im Zeitlimit von 15000 ms wie erwartet ausgeführt.
quelle
Für alle, die das Executor-Framework verwenden: Sie alle vergessen, den Executor herunterzufahren. Ändern Sie es also wie folgt:
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(); }
Wenn Sie dies nicht tun, behält Ihr Programm einen aktiven Nicht-Daemon-Thread bei und stellt sicher, dass Ihr Programm erst beendet wird, wenn Sie System.exit aufrufen
quelle
Für diejenigen, die die neue Java 8-Methode nicht verwenden können
waitFor(long timeout, TimeUnit unit)
(weil sie auf Android laufen oder einfach nicht aktualisieren können), können Sie sie einfach aus dem JDK-Quellcode rippen und irgendwo in Ihrer Utils-Datei hinzufügen: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; }
Die einzige Änderung, die ich am Original aus dem JDK8-Quellcode vorgenommen habe, ist das Hinzufügen des
Process
Parameters, damit wir dieexitValue
Methode aus dem Prozess aufrufen können.Die
exitValue
Methode versucht direkt, einen zurückzugeben oder auszulösen,IllegalThreadStateException
wenn der Prozess noch nicht beendet wurde. In diesem Fall warten wir auf das empfangene Timeout und beenden es.Die Methode gibt einen Booleschen Wert zurück. Wenn also false zurückgegeben wird, müssen Sie den Prozess manuell beenden.
Dieser Weg scheint einfacher zu sein als alles, was oben veröffentlicht wurde (erwarten Sie, dass der direkte Anruf sicher auf WaitFor wartet).
quelle
Eine leichte Lösung für kleine Apps:
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); } }
quelle
Implementieren Sie als Delegat und schlagen Sie den Anruf fehl, wenn er über Ihrem Schwellenwert liegt.
quelle
Versuchen Sie es mit einem Timer (oder Sleep ()), in einem separaten Thread oder in Ihrer Ereigniswarteschlange, falls vorhanden.
quelle
Es gibt verschiedene Möglichkeiten, dies zu tun, aber ich würde die Verwendung eines Executors in Betracht ziehen. Dies hilft Ihnen nur dabei, den Exit-Wert oder die Ausnahme vom Thread an den ursprünglichen Aufrufer zurückzugeben.
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; }
Ich denke, Sie können die Rennbedingung nicht umgehen, bei der die Wartezeit abgelaufen ist und der Prozess kurz vor dem Aufruf von destroy () beendet wird.
quelle
Ich habe auch die Worker-Implementierung getestet und arbeite wie ein Zauber. Während des Bearbeitungsprozesses io habe ich Threads hinzugefügt, um stde und stdo zu behandeln. Wenn der Worker-Thread abläuft, beende ich auch die Io-Threads.
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(); }
quelle
Als erstes einige Hintergrundinformationen, stieß ich auf das Problem, dass beim Ausführen eines Befehls eine Zeitüberschreitung auftrat, da das Programm, das ich ausführen wollte, niemals Fehler- oder Fehlerinformationen druckte und es einfach intern erneut versuchte, was dazu führte, dass der Prozess stecken blieb weil es beim erneuten Versuch nie einen Fehler oder einen Ausgabestream gab.
Also nach
process.exec()
oderprocess.start()
,Es würde für immer an dieser Linie hängen bleiben,
BufferedReader input = new BufferedReader(newInputStreamReader(process.getInputStream()));
Gemäß Java 1.8 mit
public boolean waitFor(long timeout,TimeUnit unit)
Methode sollte das Zeitlimit nach dem angegebenen Zeitlimit "idealerweise" abgelaufen sein. In meinem Fall kann es jedoch aus irgendeinem Grund zu einem Zeitlimit kommen, weil ich die Anwendung als Windows-Dienst ausgeführt habe (ich habe die Benutzerberechtigungen überprüft und alles aktiviert das Konto hat aber nicht geholfen).Also habe ich versucht, es mit der folgenden Logik zu implementieren, mit der wir den Eingabestream weiter überprüfen würden
input.ready()
und ein Timeout-Flag Diese einfache Lösung funktionierte im Vergleich zu allen anderen existierenden wie ein Zauber.Code:
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 (!process.isAlive() || 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)); } } } }
quelle
Sie können einen Thread starten, der für die gewünschte Zeit in den Ruhezustand versetzt wird, und nach dem Ruhezustand einen Booleschen Wert ändern, den Sie in Ihrer executeCommandLine-Methode durchlaufen.
So etwas in der Art (weder getestet noch kompiliert, diese Lösung ist ein Prototyp, den Sie überarbeiten sollten, wenn es Ihren Anforderungen entspricht):
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; }
quelle
und hier ist der 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; } }
quelle
Apache Commons Exec kann Ihnen dabei helfen.
Siehe 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());
quelle
Wenn ich Java 8 benutze, würde ich mit Aleksander Blomskøld antworten iepwaitFor (1, TimeUnit.MINUTE)
Wenn Sie Java 6/7 verwenden und Swing verwenden, können Sie einen SwingWorker verwenden:
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 }
quelle
Ich weiß, dass dies ein wirklich alter Beitrag ist. Ich brauchte Hilfe bei einem ähnlichen Projekt, also dachte ich, ich könnte einen Teil meines Codes geben, den ich bearbeitet habe, und einen, der funktioniert.
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;
Hoffe das hilft der Zukunft: D.
quelle