java线程等待死进程完成

时间:2012-02-15 15:06:48

标签: java multithreading process

我编写了一个java类来执行多线程任务,每个任务都运行一个外部进程。 该过程负责将“.chp”文件转换为“.txt”文件。它是用C语言编写的。

此过程在某一时刻中断,因为当我查看终端中的“顶部”时它会消失(可能是由于chp文件损坏)。问题是我的java线程中的进程没有返回。 “process.waitFor()”似乎永远持续下去(至少是我为ExecutorService指定的12小时。

我做错了什么(没有捕捉异常?)? 我尝试在MyThread中设置一个String类型的类变量,并输入一个错误消息代替抛出一个新的RuntimeException,然后在main的末尾打印String,但是线程代码没有达到这一点。它仍然停留在waitFor()。

一旦C程序失败,进程是否应该终止?

程序在终端上打印(cf:MyThread):

A
B
C

主:

String pathToBin = "/path/to/bin";
List<MyThread> threadList = new ArrayList<MyThread>();

for (File f : folderList) {
    File[] chpFilesInFolder = f.listFiles(new FilenameFilter() {

        @Override
        public boolean accept(File dir, String name) {
            if (name.endsWith(".chp")){
                 return true;
            }else{
                 return false;
            }
        }
    });
    File chpFile = writeChpFiles(chpFilesInFolder);
    String[] cmd = {pathToBin, "--arg1", chpFile, "--out-dir", outputFolder};
    MyThread t = new MyThread(cmd, f, chpFilesInFolder);
    threadList.add(t);
}

ExecutorService threadExecutor = Executors.newFixedThreadPool(4);
for(MyThread th : threadList){
    threadExecutor.execute(th);
}
threadExecutor.shutdown();

try {
    threadExecutor.awaitTermination(12, TimeUnit.HOURS);
} catch (InterruptedException e) {
    e.printStackTrace();
}

MyThread的:

class MyThread extends Thread{
    private String[] cmd;
    private File chpFolder;
    private File[] chpFilesInFolder;

    public MyThread(String[] cmd, File chpFolder, File[] chpFilesInFolder){
        this.cmd = cmd;
        this.chpFolder = chpFolder;
        this.chpFilesInFolder = chpFilesInFolder;
    }

    @Override
    public void run() {
        Process process = null;
        try{
            System.err.println("A ");
            ProcessBuilder procBuilder = new ProcessBuilder(cmd);
            procBuilder.redirectErrorStream(true);

            System.err.println("B");
            process = procBuilder.start();

            System.err.println("C");
            process.waitFor();

            System.err.println("D");
            if(process.exitValue()!=0) System.err.println("ERROR !"+process.exitValue());

            System.err.println("E");
        }catch(IOException e){
            e.printStackTrace();
        }catch(InterruptedException e){
            e.printStackTrace();
        }catch(Throwable e){
            e.printStackTrace();
        }finally{
            System.err.println("F");
            if(process!=null) {try { process.destroy();} catch(Exception err) {err.printStackTrace();}}
        }

        File[] txtFilesInFolder = chpFolder.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                if (name.endsWith(".chp.txt")){
                    return true;
                }else{
                    return false;
                }
            }
        });

        if (txtFilesInFolder.length==chpFilesInFolder.length){
            for (File chp : chpFilesInFolder) {
                chp.delete();
            }
            File logFile = new File(chpFolder, "apt-chp-to-txt.log");
               if (logFile.exists()){
                   logFile.delete();
               }
        }else{
            throw new RuntimeException("CHPs have not all been transformed to TXT in "+chpFolder.getAbsolutePath());
        }

5 个答案:

答案 0 :(得分:3)

您的C程序是否可能在stdout上生成输出?如果是这样,您需要在Process.waitFor()返回之前读取Process.getOutputStream() - 请参阅http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4254231

或者,将您的C程序调用一个重定向stdout的shell脚本。

您可以使用jstack命令确认线程确实在Process.waitFor()处被阻止。

答案 1 :(得分:0)

你可以让主线程等待一段合理的时间,然后在MyThread类上调用一些方法来杀死已启动的进程,从而导致线程完成。

答案 2 :(得分:0)

如果我没有正确理解,那么在C程序崩溃后你的Java线程仍在等待。

让衍生的C进程发送心跳。您甚至可以通过打印到控制台(或插入表格)来执行此操作,并且每隔一段时间唤醒Java线程并检查心跳。如果它不存在,则假设C进程死亡并终止线程。

答案 3 :(得分:0)

我经常建议使用更强大和专业的观点,同时使用消息解决方案使您的C程序与您的Java应用程序交互,避免那些非守护程序线程等待永远是容易和干净的您的C应用程序崩溃...现在所有代理都有一个STOMP接口,这对于任何类型的应用程序来说都非常酷(只使用任何Http库),代理配置将启用重新启动未完成的作业,放置一些超时因此,即使JMS不支持请求和响应,也很容易实现这样的范例....

HTH 杰罗姆

答案 4 :(得分:0)

在Java中启动外部进程可能会有点棘手。我经常试图避免它们,因为你将不得不处理不同的错误代码和一些终端的疯狂。我建议你使用专门的库,如commons-exec(http://commons.apache.org/exec/)<