簡體   English   中英

在Java中,如何使單個線程等待進程完成?

[英]In java, how to make a single thread to wait for a process to finish?

這是我擁有的:我有一個線程來啟動一個進程,該進程由ProcessBuilder創建,並在終端中啟動一個字符串命令。 有許多並發線程執行相同的操作,但是對不同的數據執行。

這是我想做的事情:我想創建一個線程(啟動了一個進程)以等待該進程完成。 我想出了兩種方法,但都沒有用。

方法1:使用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進程,每個進程都在不同的視頻數據上工作(沒有數據依存關系或競爭條件,或者在這里如此)。 所有這些thread1線程都是由另一個函數(main)中的另一個主線程創建和啟動的。 Linux中的操作系統。 IDE是Netbeans(可以從中獲得每個功能的描述)。 我試圖使復制粘貼的代碼盡可能短(為簡單起見),因此,如果您認為需要其他功能或程序其余部分的代碼,請通知我將其粘貼在此處。

非常感謝你,

我相信您確實需要使用單獨的線程來讀取輸入。 我沒有找到避免這種情況的方法。 我使用以下算法( 在H2數據庫中 ),對我來說效果很好。 另請注意redirectErrorStream

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

具有Process.waitFor()的方法1應該可以工作。 我認為您啟動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();
        }
    }
}

由於ping過程花費的時間遠遠超過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();

我得到了預期的輸出。 所以我認為您使用的線程錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM