0

非常に優れた記事 (When Runtime.exec() will't) には次のように書かれています。完了しない場合があります。現在のスレッドが待機する必要があるかどうかを判断するには、waitFor() メソッドを使用する代わりに、waitFor というブール値パラメーターを exitValue() メソッドに渡すことをお勧めします。exitValue() はこのメソッドのより適切な名前であり、2 つのメソッドが異なる条件下で同じ機能を実行する必要がないため、ブール値の方がより有益です。このような単純な条件判別は、入力パラメーターのドメインです。

システムコールがプロセスを開始し、ユーザーがそれを強制終了するまで実行し続けるという状況がまったく同じです。「(process.waitFor() == 0)」を使用すると、プロセスが完了しないため、そこでプログラムがブロックされます。上記の記事の著者は、「waitFor」パラメーターで exitValue() を使用できることを提案しています。誰か試してみましたか?どんな例でも役に立ちます。

コード:

// 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); 
4

3 に答える 3

3

これは、外部プロセスを起動するために使用するライブラリ コードの「大まかな」例です。

基本的に、これは 3 つのスレッドを使用します。1 つ目は、実際にコマンドを実行し、それが存在するまで待機するために使用されます。

他の 2 つは、プロセスの出力ストリームと入力ストリームを処理します。これにより、これらが互いに独立し、一方が他方をブロックできなくなります。

次に、何かが発生したときに通知されるリスナーと全体が結び付けられます。

エラー処理は改善される可能性があります (実際に何が/誰が失敗したかについて失敗条件が少し不明確であるため)、基本的な概念はそこにあります...

これは、気にせずにプロセスを起動できることを意味します...(必要になるまで)

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);

            }

        }
    }
}
于 2013-03-07T02:30:23.563 に答える
1

Before using waitFor in main thread, create another thread (child) and construct logic for your termination cases in this new thread. For example, wait for 10 secs. If the condition is fulfilled, then interrupt the main thread from the child thread ant handle the following logic on your main thread.

The following code creates a child thread to invoke the process and the main thread does its work until the child finishes successfully.

    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();
        }
    }
于 2013-03-07T00:14:35.243 に答える
1

「(process.waitFor() == 0)」を使用すると、プロセスが完了しないため、そこでプログラムがブロックされます。

いいえ、そうではありません。スレッドをブロックします。そのため、スレッドがあります。

上記の記事の著者は、「waitFor」パラメーターで exitValue() を使用できることを示唆しています

いいえ、彼はしません。彼は、誰かに尋ねられたら、どのように設計したかについて話しています。しかし、彼らはそうしませんでした、そして彼はしませんでした。

誰か試してみましたか?

できません。存在しません。

于 2013-03-07T00:42:01.967 に答える