Как использовать exitValue() с параметром?
Очень хорошая статья (когда Runtime.exec() не будет) гласит: Единственное возможное время, когда вы используете exitValue() вместо waitFor(), это когда вы не хотите, чтобы ваша программа блокировала ожидание внешнего процесса, который может никогда не завершиться. Вместо использования метода waitFor() я бы предпочел передать логический параметр waitFor в метод exitValue(), чтобы определить, должен ли текущий поток ожидать. Логическое значение будет более полезным, поскольку exitValue() является более подходящим именем для этого метода, и нет необходимости для двух методов выполнять одну и ту же функцию в разных условиях. Такое простое различение условий является областью входного параметра.
У меня точно такая же ситуация, когда мой системный вызов запускает процесс, который будет продолжаться до тех пор, пока пользователь не решит его убить. Если я использую '(process.waitFor() == 0)', это заблокирует программу, потому что процесс не будет завершен. Автор в статье выше предполагает, что exitValue() может использоваться с параметром waitFor. Кто-нибудь пробовал это? Любой пример будет полезен.
Код:
// Запускаем ProcessBuilder, 'str' содержит команду
ProcessBuilder pbuilder = new ProcessBuilder(str);
pbuilder.directory(new File("/root/workspace/Project1"));
pbuilder.redirectErrorStream(true);
Process prcs = pbuilder.start();
AForm.execStatustext.append("\n=> Process is:" + prcs);
// Read output
StringBuilder out = new StringBuilder();
BufferedReader bfrd = new BufferedReader(new InputStreamReader(process.getInputStream()));
String current_line = null, previous_line = null;
while ((current_line = bfrd.readLine()) != null) {
if (!line.equals(previous_line)) {
previous_line = current_line;
out.append(current_line).append('\n');
//System.out.println(line);
}
}
//process.getInputStream().close();
// Send 'Enter' keystroke through BufferedWriter to get control back
BufferedWriter bfrout = new BufferedWriter(new OutputStreamWriter(prcs.getOutputStream()));
bfrout.write("\\r");
bfrout.newLine();
bfrout.flush();
bfrout.write("\\r");
bfrout.newLine();
bfrout.flush();
//process.getOutputStream().close();*/
if (prcs.waitFor() == 0)
System.out.println("Commands executed successfully");
System.exit(0);
3 ответа
Перед использованием waitFor в главном потоке создайте другой поток (дочерний) и создайте логику для ваших случаев завершения в этом новом потоке. Например, подождите 10 секунд. Если условие выполнено, прервите основной поток из обработчика дочернего потока и обработайте следующую логику в основном потоке.
Следующий код создает дочерний поток для вызова процесса, и основной поток выполняет свою работу, пока дочерний процесс не завершится успешно.
import java.io.IOException;
public class TestExecution {
public boolean myProcessState = false;
class MyProcess implements Runnable {
public void run() {
//------
Process process;
try {
process = Runtime.getRuntime().exec("your command");
process.waitFor();
int processExitValue = process.exitValue();
if(processExitValue == 0) {
myProcessState = true;
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void doMyWork() {
MyProcess myProcess = new MyProcess();
Thread myProcessExecuter = new Thread(myProcess);
myProcessExecuter.start();
while(!myProcessState) {
// do your job until the process exits with success
}
}
public static void main(String[] args) {
TestExecution testExecution = new TestExecution();
testExecution.doMyWork();
}
}
Это "грубый" пример кода библиотеки, который я использую для запуска внешних процессов.
В основном, это использует три потока. Первый используется для выполнения собственно команды, а затем дождаться ее появления.
Два других имеют дело с потоками вывода и ввода процессов. Это делает их независимыми друг от друга и препятствует способности одного блокировать другого.
Все это затем связывается со слушателем, который уведомляется, когда что-то происходит.
Обработка ошибок могла бы быть лучше (поскольку условие сбоя немного неясно относительно того, что / кто на самом деле потерпел неудачу), но основная концепция есть...
Это означает, что вы можете запустить процесс, а вам все равно...(пока не захотите)
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestBackgroundProcess {
public static void main(String[] args) {
new TestBackgroundProcess();
}
public TestBackgroundProcess() {
BackgroundProcess bp = new BackgroundProcess("java", "-jar", "dist/BackgroundProcess.jar");
bp.setListener(new ProcessListener() {
@Override
public void charRead(BackgroundProcess process, char value) {
}
@Override
public void lineRead(BackgroundProcess process, String text) {
System.out.println(text);
}
@Override
public void processFailed(BackgroundProcess process, Exception exp) {
System.out.println("Failed...");
exp.printStackTrace();
}
@Override
public void processCompleted(BackgroundProcess process) {
System.out.println("Completed - " + process.getExitValue());
}
});
System.out.println("Execute command...");
bp.start();
bp.send("dir");
bp.send("exit");
System.out.println("I'm not waiting here...");
}
public interface ProcessListener {
public void charRead(BackgroundProcess process, char value);
public void lineRead(BackgroundProcess process, String text);
public void processFailed(BackgroundProcess process, Exception exp);
public void processCompleted(BackgroundProcess process);
}
public class BackgroundProcess extends Thread {
private List<String> commands;
private File startIn;
private int exitValue;
private ProcessListener listener;
private OutputQueue outputQueue;
public BackgroundProcess(String... cmds) {
commands = new ArrayList<>(Arrays.asList(cmds));
outputQueue = new OutputQueue(this);
}
public void setStartIn(File startIn) {
this.startIn = startIn;
}
public File getStartIn() {
return startIn;
}
public int getExitValue() {
return exitValue;
}
public void setListener(ProcessListener listener) {
this.listener = listener;
}
public ProcessListener getListener() {
return listener;
}
@Override
public void run() {
ProcessBuilder pb = new ProcessBuilder(commands);
File startIn = getStartIn();
if (startIn != null) {
pb.directory(startIn);
}
pb.redirectError();
Process p;
try {
p = pb.start();
InputStreamConsumer isc = new InputStreamConsumer(p.getInputStream(), this, getListener());
outputQueue.init(p.getOutputStream(), getListener());
outputQueue.start();
p.waitFor();
isc.join();
outputQueue.terminate();
outputQueue.join();
ProcessListener listener = getListener();
if (listener != null) {
listener.processCompleted(this);
}
} catch (InterruptedException ex) {
ProcessListener listener = getListener();
if (listener != null) {
listener.processFailed(this, ex);
}
} catch (IOException ex) {
ProcessListener listener = getListener();
if (listener != null) {
listener.processFailed(this, ex);
}
}
}
public void send(String cmd) {
outputQueue.send(cmd);
}
}
public class OutputQueue extends Thread {
private List<String> cmds;
private OutputStream os;
private ProcessListener listener;
private BackgroundProcess backgroundProcess;
private ReentrantLock waitLock;
private Condition waitCon;
private boolean keepRunning = true;
public OutputQueue(BackgroundProcess bp) {
backgroundProcess = bp;
cmds = new ArrayList<>(25);
waitLock = new ReentrantLock();
waitCon = waitLock.newCondition();
}
public ProcessListener getListener() {
return listener;
}
public OutputStream getOutputStream() {
return os;
}
public BackgroundProcess getBackgroundProcess() {
return backgroundProcess;
}
public void init(OutputStream outputStream, ProcessListener listener) {
os = outputStream;
this.listener = listener;
}
public void send(String cmd) {
waitLock.lock();
try {
cmds.add(cmd);
waitCon.signalAll();
} finally {
waitLock.unlock();
}
}
public void terminate() {
waitLock.lock();
try {
cmds.clear();
keepRunning = false;
waitCon.signalAll();
} finally {
waitLock.unlock();
}
}
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
BackgroundProcess backgroundProcess = getBackgroundProcess();
ProcessListener listener = getListener();
OutputStream outputStream = getOutputStream();
try {
while (keepRunning) {
while (cmds.isEmpty() && keepRunning) {
waitLock.lock();
try {
waitCon.await();
} catch (Exception exp) {
} finally {
waitLock.unlock();
}
}
if (!cmds.isEmpty()) {
waitLock.lock();
try {
while (!cmds.isEmpty()) {
String cmd = cmds.remove(0);
System.out.println("Send " + cmd);
outputStream.write(cmd.getBytes());
outputStream.write('\n');
outputStream.write('\r');
outputStream.flush();
}
} finally {
waitLock.unlock();
}
}
}
} catch (IOException ex) {
if (listener != null) {
listener.processFailed(backgroundProcess, ex);
}
}
}
}
public class InputStreamConsumer extends Thread {
private InputStream is;
private ProcessListener listener;
private BackgroundProcess backgroundProcess;
public InputStreamConsumer(InputStream is, BackgroundProcess backgroundProcess, ProcessListener listener) {
this.is = is;
this.listener = listener;
this.backgroundProcess = backgroundProcess;
start();
}
public ProcessListener getListener() {
return listener;
}
public BackgroundProcess getBackgroundProcess() {
return backgroundProcess;
}
@Override
public void run() {
BackgroundProcess backgroundProcess = getBackgroundProcess();
ProcessListener listener = getListener();
try {
StringBuilder sb = new StringBuilder(64);
int in = -1;
while ((in = is.read()) != -1) {
char value = (char) in;
if (listener != null) {
listener.charRead(backgroundProcess, value);
if (value == '\n' || value == '\r') {
if (sb.length() > 0) {
listener.lineRead(null, sb.toString());
sb.delete(0, sb.length());
}
} else {
sb.append(value);
}
}
}
} catch (IOException ex) {
listener.processFailed(backgroundProcess, ex);
}
}
}
}
Если я использую '(process.waitFor() == 0)', это заблокирует программу, потому что процесс не будет завершен.
Нет, не будет. Это заблокирует поток. Вот почему у вас есть темы.
Автор в статье выше предполагает, что exitValue() можно использовать с параметром waitFor
Нет, он не Он говорит о том, как бы он это спроектировал, если бы кто-нибудь спросил его. Но они этого не сделали, а он нет.
Кто-нибудь пробовал это?
Ты не можешь Не существует