How to interrupt BufferedReader's readLine

后端 未结 9 1398
醉梦人生
醉梦人生 2020-11-29 07:56

I am trying to read input from a socket line by line in multiple threads. How can I interrupt readLine() so that I can gracefully stop the thread that it\'s bl

9条回答
  •  借酒劲吻你
    2020-11-29 08:24

    Sorry for being over 6 years late ;-) I had a need for some interruptible readLine when reading from the keyboard, for a simple hobby console application. In other words, I couldn't "close the socket".

    As you may know, System.in is an InputStream that apparently already does some buffering (you need to press Enter]). However, it seems to be suggested to wrap it in a BufferedReader for better efficiency, so my input is from:

    BufferedReader consoleIn = new BufferedReader(new InputStreamReader(System.in));

    The other thing one might have discovered is that BufferedReader.readLine() blocks until input is provided (even if the thread is interrupted, which seems to only end the thread once readline() gets its input). It is however possible to predict when BufferedReader.read() will not block, by calling BufferedReader.ready() == true. (However, == false does not guarantee a block, so beware.)

    So I have incorporated the above ideas into a method that reads the BufferedReader character by character, checking in between each character if the thread has been interrupted, and also checks for end-of-line, at which point the line of text is returned.

    You may find this code useful, pass the consoleIn variable as declared above. (Criticism may be welcomed too...):

    private String interruptibleReadLine(BufferedReader reader)
            throws InterruptedException, IOException {
        Pattern line = Pattern.compile("^(.*)\\R");
        Matcher matcher;
        boolean interrupted = false;
    
        StringBuilder result = new StringBuilder();
        int chr = -1;
        do {
            if (reader.ready()) chr = reader.read();
            if (chr > -1) result.append((char) chr);
            matcher = line.matcher(result.toString());
            interrupted = Thread.interrupted(); // resets flag, call only once
        } while (!interrupted && !matcher.matches());
        if (interrupted) throw new InterruptedException();
        return (matcher.matches() ? matcher.group(1) : "");
    }
    

    ... And in the thread that is calling this, catch the exceptions and end the thread appropriately.

    This was tested in Java 8 on Linux.

提交回复
热议问题