Search code examples
javamultithreadingcmddestroy

End Thread that is stuck in a InputStream.read() loop


I start a cmd application that outputs to System.out through this SyncPipe Runnable:

public class SyncPipe implements Runnable {

    private final InputStream is;
    private final OutputStream os;

    public SyncPipe(InputStream is, OutputStream os) {
        this.is = is;
        this.os = os;
    }

    public void run() {
        try {
            final byte[] buffer = new byte[1024];
            for ( int length = 0; ( length = is.read(buffer) ) != -1; )
                os.write(buffer, 0, length);
            System.out.print("stopped");
        } catch ( Exception ex ) { 
            ex.printStackTrace(); 
        }
    }

}

I start RunIt with cmd = "C:/bin/read.exe -f D:/test.jpg"

private class RunIt implements Runnable {

    public int p;
    public String cmd;

    public RunIt (int p, String cmd) {
        this.p = p;
        this.cmd = cmd;
    }

    public void run() {
        ProcessBuilder pb = new ProcessBuilder("cmd");
        try {
            process = pb.start();
            (new Thread(new SyncPipe(process.getErrorStream(), System.err))).start();
            (new Thread(new SyncPipe(process.getInputStream(), System.out))).start();
            OutputStream out = process.getOutputStream();
            out.write((cmd + "\r\n").getBytes());
            out.flush();
            out.close();

            try {
                process.waitFor();
            } catch ( InterruptedException e ) {
                e.printStackTrace();
            }

            println("Stopped using %d.", p);
        } catch ( IOException ex ) {
            ex.printStackTrace();
        }
    }

}

My question now: How can I make (new Thread(new SyncPipe(process.getErrorStream(), System.err))) die? Giving SyncPipe a boolean variable stop, setting it true during runtime, and checking for it via for ( int length = 0; ( length = is.read(buffer) ) != -1 && !stop; ) did not do the trick.

Thanks a lot in advance.


I ended up doing the work-around that @Gray suggested. It works now:

public void run() {
    try {
        final byte[] buffer = new byte[1024];
        do
            if ( is.available() > 0 ) {
                int length = is.read(buffer);
                if ( length != -1 )
                    os.write(buffer, 0, length);
                else
                    stop = true;
            }
        while ( !stop );
    } catch ( Exception ex ) { 
        ex.printStackTrace(); 
    }
}

Solution

  • The thread will read EOS and exit when the underlying process exits. You don't have to do anything special about it yourself.

    EDIT It seems to me from reading your comments to other answers that your real problem is ending the process. These threads will come unstuck as soon as that happens. You're attacking the wrong end of the problem.