运行多个进程的Java runtime.exec()

4

我的程序中有一个由n个项目组成的列表。

我将遍历这个列表,并启动如下进程:

Runtime.getRuntime.exec("cmd /C start abc.bat"+listitem() )

我需要维护4个进程的计数。一旦其中任何一个进程完成,我需要启动下一个进程,因此进程计数应为4。

我能够同时启动4个进程,但不确定如何保持计数为4。基本上,我需要一些通知来告诉我进程何时终止,以便我可以启动下一个进程,任何线程都可以。

关于如何实现这一点,有人能分享一段代码吗?

4个回答

12

使用大小为4的ThreadPoolExecutor和一个Runnable实现,该实现启动Process并调用Process.waitFor()。由于线程池将被限制为4个线程,并且所有4个线程都将启动进程然后等待它,因此您可以确保不会有多于4个子进程在运行。

以下是一些示例代码,可帮助您完成这项任务:

ExecutorService executor = Executors.newFixedThreadPool(4);

executor.execute(new Runnable() {
    public void run() {
        //use ProcessBuilder here to make the process
        Process p = processBuilder.start();
        p.waitFor();
    }
});

主线程?入口线程?我不会为OP编写程序,只是指出一个好的方向。 - Tim Bender
@ Tim Bender:+1。恭喜您达成了一万个赞的目标 :) - Jayan

2
 public class ProcessRunner {

    public static void main(String[] args) throws IOException, InterruptedException {
        //Creating n threads as required
        ExecutorService exec = Executors.newFixedThreadPool(4);
        for(int i = 0; i < 4; i++){
            exec.execute(new ProcessRunnable());
        }

        Thread.sleep(10000);

        //whenever you want them to stop
        exec.shutdownNow();

    }   

}

class ProcessRunnable implements Runnable{
       @Override
       public void run(){
        do{
           Process p;
        try {
            p = Runtime.getRuntime().exec("cd ..");
            p.waitFor(); 
        } catch (IOException e) {
                    //Take appropriate steps
            e.printStackTrace();
        } catch (InterruptedException e) {
                    //Take appropriate steps
            e.printStackTrace();
        }

        }while(!Thread.interrupted());
       }
}

Process#waitFor()

该方法会使当前线程等待,直到由该Process对象表示的进程终止。如果子进程已经终止,则此方法立即返回。如果子进程尚未终止,则调用线程将被阻塞,直到子进程退出。


感谢您的及时回复。我尝试了使用线程池计数为4的方法,但是在启动和完成4个进程后,执行终止了。线程在4个进程之后没有被调用。有什么建议吗? - Vigneshwaran
@user2644818 我已经编辑了代码,包括对我有效的代码。这4个线程不断运行该进程,并在其退出后立即在while循环中再次运行它,直到您调用shutdownNow() - Narendra Pathai

1
你应该有四个线程,每个线程从池中获取一个任务,执行完后再执行下一个任务。实现方式如下:
class Whatever extends Thread {
    public void run() {
        while (!interrupted()) {
            String str = listitem();
            if (str == null) // there are no more commands to run
                break;
            Runtime.getRuntime.exec(("cmd /C start abc.bat"+str).split("\\s")).waitFor();
}

然后启动这四个线程。

1
这个解决方案所做的就是将问题从管理子进程生命周期转变为管理线程生命周期。向其他回答者学习,像我在我的回答中提到的那样加入ExecutorService。 - Tim Bender
@TimBender的示例非常完整,其中包含了Runtime.getRuntime,我可以直接将其完整地复制粘贴到我的代码中。如果你也这样做了,你的答案可能就是正确的... - Radu
@Radu SO的目的不一定是创建复制/粘贴答案,而是提供好的答案。我的评论仍然很有价值,这个答案质量很低,但是OP有权选择任何他们想要的答案。 - Tim Bender
@TimBender 正如你所说,人们有权选择。而我先生,选择不让自己的头脑被所有关于东西的东西所淹没。 - Radu
2
@Radu 当然可以。https://dev59.com/onRB5IYBdhLWcg3wtZMV https://dev59.com/2mgv5IYBdhLWcg3wQ-ud - Tim Bender
我有一个小问题,这行代码 Runtime.getRuntime.exec() 是在主线程还是后台线程上运行的?谢谢! - Hilal

1
您可以使用大小为4的固定线程池,确保在任何给定时刻最多只有4个活动线程。
    final ExecutorService ex = Executors.newFixedThreadPool(4);
    for(int i = 0; i < 100; i++) {
        ex.execute(new Runnable() {
            @Override
            public void run() {
              ... run the process here and wait for it to end
            }
        });
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接