vitaut
vitaut

Reputation: 55755

How to stop a thread waiting in a blocking read operation in Java?

I have a thread that executes the following code:

public void run() {
    try {
        int n = 0;
        byte[] buffer = new byte[4096];
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
            out.flush();
        }
    } catch (IOException e) {
        System.out.println(e);
    }
}

where in is System.in. How can I stop such thread gracefully? Neither closing System.in, nor using Thread.interrupt appear to work.

Upvotes: 22

Views: 22715

Answers (7)

tdx
tdx

Reputation: 31

Is it safe to close in stream in other thread? It works for me. In this case, in.read(...) throws exception SocketException.

Upvotes: 2

Nans
Nans

Reputation: 156

I had the same problem today, and this is how I fixed it, using in.ready() :

public void run() {
    String line;
    // Some code

    while(!Thread.currentThread().isInterrupted()){
        try {
            if (in.ready()) {
                line = in.readLine();
            } 
        } catch (Exception e) {
            try {
                Thread.currentThread().wait(500);
            } catch (InterruptedException e1) {
                // Do what we want when thread is interrupted
            }
        }
    }
}

Upvotes: 0

Denis Tulskiy
Denis Tulskiy

Reputation: 19187

You've stumbled upon a 9 year old bug no one is willing to fix. They say there are some workarounds in this bug report. Most probably, you'll need to find some other way to set timeout (busy waiting seems unavoidable).

Upvotes: 8

Andreas Dolk
Andreas Dolk

Reputation: 114847

If you want to give a user some time to enter data - maybe to allow overriding default values or interrupting some automated process -, then wait first and check available input after the pause:

System.out.println("Enter value+ENTER within 5 Seconds to override default value: ");
try{
  Thread.sleep(5000);
} catch {InterruptedException e){}

try{
  int bytes = System.in.available();
  if (bytes > 0) {
    System.out.println("Using user entered data ("+size+" bytes)");
  } else {
    System.out.println("Using default value"); 
  }
} catch(IOException e) { /*handle*/ }

Upvotes: 0

asela38
asela38

Reputation: 4654

you can use a external flag for this

boolean flag = true;


public void run() { 
    try { 
        int n = 0; 
        byte[] buffer = new byte[4096]; 
        while ((n = in.read(buffer)) != -1 && flag) { 
            out.write(buffer, 0, n); 
            out.flush(); 
        } 
    } catch (IOException e) { 
        System.out.println(e); 
    } 
} 

Upvotes: -3

Paolo
Paolo

Reputation: 22646

You could use the available() method (which is non-blocking) to check whether there is anything to read beforehand.

In pseudo-java:

//...
while(running)
{
    if(in.available() > 0)
    {
        n = in.read(buffer);
        //do stuff with the buffer
    }
    else
    {
        Thread.sleep(500);
    }
}
//when running set to false exit gracefully here...

Upvotes: 2

PeterMmm
PeterMmm

Reputation: 24640

This is because reading System.in (InputStream) is a blocking operation.

Look here Is it possible to read from a InputStream with a timeout?

Upvotes: 8

Related Questions