简体   繁体   中英

Java Asynchronous process runner with inputstream reader using Futuretask

I'm trying to run an asynchronous process and getting its inputstream (if there is).

This is my code:

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

and this is the process run Task

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

}

I can't get the process output, please mind 2 very important thing:

  • Process must be async because I need to manage a timeout
  • Process's InputStream can be optional and must not lock the thread waiting for content: there can be a process without any output.

UPDATE

I'm trying this version... seems to work but I don't know if it is strong enought.

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

The behavior that is observing the process' output should be itself in an own thread. Once the process is terminated, this thread should be terminated, too.

So basically you can do this:

@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.
    }
}

A couple of notes:

  • I did not test any code. Maybe I made some subtle mistakes, but the direction should be clear.
  • Usually I would not extend Thread but rather implement Runnable . I simply wanted to not over-complicate things.
  • I did not provide code for copying bytes from an input stream to an output stream. If you need help on this, do a little search in the web. You will find many solutions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM