2014-10-17 3 views
1

비동기 프로세스를 실행하고 해당 입력 스트림을 얻으려고합니다 (있는 경우). Futuretask를 사용하는 입력 스트림 리더가있는 Java 비동기 프로세스 러너

내 코드입니다 :

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

} 

실행하는 과정입니다 :

  • 시간 제한을 관리해야하기 때문에 프로세스가 비동기 여야합니다.
  • 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을 구현합니다. 나는 단순히 복잡한 것을 지나치게 복잡하게 만들고 싶지 않았습니다.
  • 입력 스트림에서 출력 스트림으로 바이트를 복사하는 코드를 제공하지 않았습니다. 이에 대한 도움이 필요하면 웹에서 약간의 검색을하십시오. 많은 솔루션을 찾을 수 있습니다.