2013-03-06 79 views
0

一篇非常好的文章(當Runtime.exec()不會)說:只有當你不希望你的程序阻塞等待外部時,你纔會使用exitValue()而不是waitFor過程可能永遠不會完成。我寧願將一個名爲waitFor的布爾參數傳遞給exitValue()方法,以確定當前線程是否應該等待,而不是使用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); 
+0

在一個單獨的線程中啓動你的進程。監視它內部的退出狀態,允許程序繼續運行...您需要定義某種回調方案,以允許感興趣的方知道應用程序何時終止或它的輸出... – MadProgrammer 2013-03-06 23:52:08

+0

@MadProgrammer感謝信息。在上面顯示的代碼中,我在哪裏啓動一個線程,如果進程因錯誤而退出,我該如何處理它。目前,如果由於錯誤而退出進程,則會在stdout上輸出錯誤消息。 – 2013-03-07 00:15:11

回答

1

在主線程中使用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(); 
     } 
    } 
+0

有點困惑。我不想要進程終止。只有在執行失敗時纔可以退出。你能不能在上面的代碼中顯示它?謝謝。 – 2013-03-07 00:36:30

+0

子進程是我的進程,它產生一個系統命令並等待完成。根據上面的代碼,如果命令以錯誤結束,doMyWork中的循環永遠不會結束。只有當命令以成功結束時,doMyWork纔會結束。如果你想在失敗時退出,請改變代碼,如果(processExitValue!= 0){myProcessState = true; } – serkan 2013-08-02 21:07:05

1

如果使用 '(process.waitFor()== 0)',它會阻止程序那裏,因爲過程中不會完成。

沒有也不會。它會阻塞線程。這就是爲什麼你有線程。以上文章

作者建議exitValue()可以用 'WAITFOR' 參數

沒有使用他沒有。如果有人問他,他正在談論他將如何設計它。但他們沒有,而他沒有。

有沒有人嘗試一下?

你不行。它不存在。

3

這是我用來啓動外部進程的一些庫代碼的「粗略」示例。

基本上,這使用三個線程。第一個用於執行實際的命令,然後等待它存在。

另外兩個處理輸出流和輸入流。這使得這些彼此獨立阻止了一方阻止另一方的能力。

然後整個事情與一個事件發生時通知的偵聽器綁定在一起。

錯誤處理可能會更好(如故障條件是什麼/誰真正失敗有點不清楚),但基本的概念是有...

這意味着你可以啓動過程,而不是(直到你想要)

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

      } 

     } 
    } 
} 
+0

如果這種功能是Java,那將會很好。 – johnsam 2014-12-13 00:53:07

+0

@johnsam是的,但後來人們會抱怨說它太不靈活了;;) – MadProgrammer 2014-12-13 01:23:24

+0

不幸的是我跑sudo -l這個程序。它卡住了。 java -cp。 TestBackgroundProcess [sudo] john的密碼:發送 johnsam 2014-12-13 12:21:24