简体   繁体   中英

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.

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

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

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).

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

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

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

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*/ }

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

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