Как использовать 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

Нет, он не Он говорит о том, как бы он это спроектировал, если бы кто-нибудь спросил его. Но они этого не сделали, а он нет.

Кто-нибудь пробовал это?

Ты не можешь Не существует

Другие вопросы по тегам