2014-01-30 135 views
0

這裏是我有: 我有一個線程啓動一個進程,這個進程是由ProcessBuilder創建的,並在終端啓動一個字符串命令。有許多併發線程執行相同的操作,但數據不同。在java中,如何讓一個線程等待一個進程完成?

這是我想要做的: 我想讓一個線程(啓動一個進程)等待該進程,直到完成。我想出了兩種方法,但都沒有工作。方法1:使用process.waitFor();方法1:使用process.waitFor();方法2:使用process.waitFor();這會導致所有併發線程等待一個進程(通常是第一個進程)完成。 waitFor()的描述;說它讓一個線程等待,但這不是它所做的,它實際上使所有線程都等待。因此該程序不再是併發的。方法2:運行另一個從該進程讀取管道流的線程,等待直到有流,然後運行在該進程之後應該運行的函數。缺點是現在有很多線程,所以我不喜歡使用這種方法。這種方法的另一個問題是,我很困惑應該使用哪個過程屬性? OutputStream,InputStream或ErrorStream?

下面是代碼:

public class Thread1 extends Thread{ 
private String[] incommand; //this is the command for the process builder 
private String newoutputfile; 
InputStream ins = null; 
Reader r = null; 
BufferedReader br = null; 
ProcessBuilder pbtx = null; 

public Thread1(String[] incommand, String newoutputfile){ 
    super("Thread1"); 
    this.incommand = incommand;   
    this.newoutputfile = newoutputfile; 
    this.pbtx = new ProcessBuilder(); 
} 
@Override 
public void run(){ 
    try{      
       pbtx.command(incommand);          
       Process ptx = pbtx.start(); 
       //to make sure job is done 
       ptx.waitFor(); //problem is apparently here 
       // made sure job is done 
       //the next function is supposed to run after the process is finished     
        rite();      
       // 
      } catch (IOException ex){ 
       System.out.println("exception in thread t1"); 
       ex.printStackTrace(); 
      } 
      catch (InterruptedException yo){ 
      System.out.println("exception in thread t1"); 
      } 
      } 

順便說一句,這個過程是一個ffmpeg的過程,每個過程的工作在不同的視頻數據(沒有數據依賴或種族的狀況或什麼那麼這裏)。所有這些線程1線程由另一個函數(main)中的另一個主線程創建並啓動。 Linux中的操作系統。 IDE是Netbeans(這是我得到每個函數的描述)。我試圖儘量縮短複製粘貼的代碼(爲了簡單起見),所以如果您認爲需要其他函數或其他程序的代碼,請通知我將其粘貼到此處。

非常感謝你,

+0

你是如何開始你的線程?我嚴重懷疑Process.waitFor()凍結了所有的線程。 – Kayaman

+0

謝謝你的回答。線程由threadobject.start()啓動,然後在主程序中啓動threadobject.join()。不使用.join()會導致線程爭奪他們的輸入變量。 – user2452253

+0

那麼,使用'.join()'會導致線程等待。 'Process.waitFor()'與它無關。 – Kayaman

回答

1

我相信你需要使用單獨的線程來讀取輸入;我沒有找到避免它的方法。我使用以下算法(in the H2 database),它對我來說工作正常。請注意0​​:

ProcessBuilder pb = new ProcessBuilder(); 
pb.command(cmd.array()); 
pb.redirectErrorStream(true); 
Process p = pb.start(); 
copyInThread(p.getInputStream(), quiet ? null : sysOut); 
p.waitFor(); 
return p.exitValue(); 

private static void copyInThread(final InputStream in, final OutputStream out) { 
    new Thread() { 
     @Override 
     public void run() { 
      try { 
       while (true) { 
        int x = in.read(); 
        if (x < 0) { 
         return; 
        } 
        if (out != null) { 
         out.write(x); 
        } 
       } 
      } catch (Exception e) { 
       throw new RuntimeException(e); 
      } 
     } 
    } .start(); 
} 
+0

謝謝你的回答。隨着這段代碼的一些修改,我的程序正在工作。這裏唯一的缺點是現在創建的線程太多了。 – user2452253

+0

哦,順便說一句,我必須刪除該p.waitFor();再次因爲它會導致舊問題,所有線程和進程都停止運行,除了正在等待的進程。 – user2452253

+0

我認爲在這種情況下並不是真的需要p.waitFor(),但奇怪的是我使用它並從未看到它的任何問題... –

0

方法1與Process.waitFor()應該工作。我認爲你開始錯誤的Thread1。

這是一個簡單的例子。你可以複製它並嘗試它。 StackOverflowPinger開始一個新的ping過程。

public class StackOverflowPinger implements Runnable{ 

    public StackOverflowPinger(int id){ 
     this.id = id; 
    } 

    private int id; 

    @Override 
    public void run() { 
     try { 
      ProcessBuilder pbuilder = new ProcessBuilder(); 
      Process pingprocess = pbuilder.command("ping", "www.stackoverflow.com").start();   
      int pingresult = pingprocess.waitFor(); 
      if(pingresult == 0) 
       System.out.println("Pinger Nr." + this.id + " successfully pinged stackoverflow."); 
     } catch (IOException | InterruptedException e) { e.printStackTrace(); } 
    } 
} 

Sleeper的休眠250毫秒。

public class Sleeper implements Runnable{ 

    public Sleeper(int id){ 
     this.id = id; 
    } 

    private int id; 

    @Override 
    public void run() { 
     try { 
      Thread.sleep(250); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Sleeper " + this.id + " finished sleeping."); 
    } 
} 

這裏是實例化和啓動線程的Main。

public class ProcessMain { 

    public static void main(String[] args) { 
     for(int i = 0 ; i<4; i++){ 
      new Thread(new StackOverflowPinger(i)).run(); 
      new Thread(new Sleeper(i)).run(); 
     } 
    } 
} 

由於平過程比250毫秒更長的預期輸出應該是這樣的。

Sleeper 3 finished sleeping. 
Sleeper 0 finished sleeping. 
Sleeper 1 finished sleeping. 
Sleeper 2 finished sleeping. 
Pinger Nr.0 successfully pinged stackoverflow. 
Pinger Nr.1 successfully pinged stackoverflow. 
Pinger Nr.3 successfully pinged stackoverflow. 
Pinger Nr.2 successfully pinged stackoverflow. 

但是實際輸出是這樣的。

Pinger Nr.0 successfully pinged stackoverflow. 
Sleeper 0 finished sleeping. 
Pinger Nr.1 successfully pinged stackoverflow. 
Sleeper 1 finished sleeping. 
Pinger Nr.2 successfully pinged stackoverflow. 
Sleeper 2 finished sleeping. 
Pinger Nr.3 successfully pinged stackoverflow. 
Sleeper 3 finished sleeping. 

只有當我改變行

new Thread(new StackOverflowPinger(i)).run(); 
new Thread(new Sleeper(i)).run(); 

new Thread(new StackOverflowPinger(i)).start(); 
new Thread(new Sleeper(i)).start(); 

我得到預期的輸出。所以我認爲你正在使用你的線程錯誤。

+0

你好,謝謝你的詳細解答。然而,我以類似的方式啓動線程。除了.start()之後,我必須使用.join()線程來防止任何競爭條件超過它們的輸入變量。問題依然存在。 – user2452253

相關問題