2014-10-17 35 views
1

我试图运行一个异步过程并获取它的输入流(如果有的话)。Java使用Futuretask输入流阅读器的异步流程亚军

这是我的代码:

CommandCall commandCall = new CommandCall(commands); 
    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    Future<Integer> task = executor.submit(commandCall); 

,这是运行任务

public class CommandCall implements Callable<Integer> { 

    private byte[] output; 
    private int retval=-1; 
    private String[] commands=null; 
    Process process=null; 

    public CommandCall(String[] commands) throws Exception { 
     this.commands=commands; 
     this.output=null; 
    } 

    public void destroy() { 
     try { 
      if(process!=null) process.destroy(); 
     }catch(Exception e){} 
    } 

    public byte[] getByteArray() { 
     return output; 
    } 


    public int getRetval() { 
     return retval; 
    } 

    @Override 
    public Integer call() throws Exception { 
     try{ 
      process = new ProcessBuilder(commands).start(); 
      // here i must read the process input and store it to this.output 
      // this must be a non lockable read because the process can be without any output 
      retval= process.waitFor(); 
     }finally{ 
      try{ 
       if(bos!=null) bos.close(); 
      }catch(Exception e){} 
     } 
     return retval; 
    } 

} 

我不能让输出的过程,请介意的2个非常重要的过程:

  • 过程必须是异步的,因为我需要管理超时
  • Pro cess的InputStream可以是可选的,并且不能锁定等待内容的线程:可以有一个没有任何输出的进程。

UPDATE

我想这个版本...似乎工作,但我不知道它是强大到足够多。

@Override 
public Integer call() throws Exception { 
    InputStream is=null; 
    try{ 
     process = new ProcessBuilder(commands).start(); 
     is=process.getInputStream(); 
     int len; 
     int size = 1024; 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     byte[] buf = new byte[size]; 
     while ((len = is.read(buf, 0, size)) != -1) 
      bos.write(buf, 0, len); 
     output = bos.toByteArray(); 
     retval= process.waitFor(); 
    }finally{ 
     try{ 
      if(is!=null) is.close(); 
     }catch(Exception e){} 
    } 
    return retval; 
} 

回答

0

观察进程输出的行为本身应该在自己的线程中。一旦进程终止,该线程也应该终止。

所以基本上你可以这样做:

@Override 
public Integer call() throws Exception { 
    Thread outputObserver = null; 

    try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) { 
     this.process = new ProcessBuilder(commands).start(); 
     outputObserver = new OutputObserver(process.getInputStream(), baos); 
     outputObserver.start(); 
     this.retval = process.waitFor(); 
     this.output = baos.toByteArray(); 
    }finally{ 
     if(outputObserver != null) outputObserver.interrupt(); 
    } 

    return this.retval; 
} 

private static OutputObserver extends Thread { 
    private final InputStream input; 
    private final OutputStream output; 

    OutputObserver(InputStream input, OutputStream output) { 
     this.input = input; 
     this.output = output; 
    } 

    @Override 
    public void run() { 
     while(!Thread.interrupted()) { 
      // Copy bytes from input to output here (handling any exceptions). 
      // Maybe use 3rd party libs for that. 
     } 
     // Make sure to copy remaining bytes here, too. 
    } 
} 

有两点要注意:

  • 我没有测试任何代码。也许我犯了一些微妙的错误,但方向应该清楚。
  • 通常我不会延伸Thread,而是实施Runnable。我只是想不要让事情过分复杂化。
  • 我没有提供将输入流中的字节复制到输出流的代码。如果您需要帮助,请在网上进行一些搜索。你会发现很多解决方案。