Executor框架future.get()挂起

时间:2013-09-17 20:11:25

标签: java multithreading

我有以下运行进程的代码,我想知道运行时是否有异常。它没有任何理由挂起

Runtime runtime = Runtime.getRuntime();
proc = runtime.exec(command.toString());
ProcessHandler errorStream = new ProcessHandler(proc.getErrorStream(),"ERROR", rdyFilePath);
ExecutorService pool = Executors.newSingleThreadExecutor();
Future future = pool.submit(errorStream);
pool.shutdown();

try {
     if(future.get() == null) {
         log.info("Done completing error thread");
     }
} catch (InterruptedException | ExecutionException e) {
     e.printStackTrace();
}

这是进程处理程序的类

public class ProcessHandler implements Callable<Integer> {

    private static Logger log = Logger.getLogger(ProcessHandler.class.getName());

    InputStream inpStr;
    String strType;
    String rdyFile;


    public ProcessHandler(InputStream inpStr, String strType, String rdyFile) {
        this.inpStr = inpStr;
        this.strType = strType;
        this.rdyFile = rdyFile;
    }

    public Integer call() throws FileMetadataException {
        StringBuffer sb = new StringBuffer();
        try {

            InputStreamReader inpStrd = new InputStreamReader(inpStr);
            BufferedReader buffRd = new BufferedReader(inpStrd);
            String line = null;
            while((line = buffRd.readLine()) != null) {
                if("ERROR".equalsIgnoreCase(strType)) {

                    sb.append(line + "\n");
                    log.info(strType + "->" + line);
                }
            }
            if(sb != null) {
                log.info("Error Stream length : " + sb.length());
                throw new RuntimeException();

            }

            buffRd.close();
        } catch(IOException e) {
            log.error("IOException in ProcessHandler Thread" + e.fillInStackTrace());
            System.err.println(e);
            throw new FileMetadataException();
        } finally {
            if(sb != null) {
                if(sb.toString().length() > 0 ) {
                    log.error("Error string buffer length " + sb.length());
                    // do not create rdy file
                } else {
                    log.error("Error string buffer length : " + sb.length());
                    File f = new File(rdyFile);
                        try {
                            f.createNewFile();
                        } catch(IOException e) {
                            log.error("IOException while creating rdy file");
                        }
                    }
                    // create rdy file. 
                }
            }
            return sb.length();
        }

    }
}

2 个答案:

答案 0 :(得分:2)

  

我有以下运行进程的代码,我想知道运行时是否有异常。它没有任何理由挂起

如果您的future.get()应该使用ExecutionException引发异常 - 它就不会“挂起”。你确定你的异常没有打印但是在日志或控制台输出中丢失了吗?

在跟踪代码时,我认为程序在完成读取流后无法完成。也许正在读取其错误流的进程仍在运行且InputStream尚未关闭?也许有很多输出你用StringBuffer填充核心(应该改为StringBuilder btw)。

您是否可以使用jconsole附加到您的应用程序,以查看该线程是否仍在运行,如果是,它在做什么?

 if(future.get() == null) {
     log.info("Done completing error thread");
 }

因此,如果您从null方法返回call(),则只会记录输出。这绝不会发生,因为唯一的回报是return sb.length();。因此,要么您将从call()获得例外,否则您的结果将为非空Integer

答案 1 :(得分:2)

来自Process javadoc:

  

由于某些本机平台仅为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞,甚至死锁。

根据此警告,您的future.get()方法正在挂起,因为您只使用了来自流程对象的错误流。在我曾经使用Process个对象的所有平台上,我发现你需要同时使用Error和Standard out流。

This是一个很好的工具,它使用多线程方法来确保消耗进程流。

在这种情况下,由于您似乎不关心流程的标准输出,您可以添加类似的内容,借用StreamHelper类:

StreamHelper inStreamHelper = new StreamHelper(proc.getInputStream());
inStreamHelper.start();