代码之家  ›  专栏  ›  技术社区  ›  Jack Edmonds

如何中断BufferedReader的readLine

  •  36
  • Jack Edmonds  · 技术社区  · 14 年前

    readLine() 这样我就可以优雅地阻止它阻塞的线程了?

    编辑(悬赏) :这可以在不关闭插座的情况下完成吗?

    9 回复  |  直到 13 年前
        1
  •  24
  •   Steve Emmerson    14 年前

    关闭中断线程上的套接字。这将导致在中断的线程上引发异常。

    关于这个和其他并发问题的更多信息,我强烈推荐Brian Goetz的书“Java并发实践”。

        2
  •  30
  •   Tom Hawtin - tackline    13 年前

    难题不在于 BufferedReader.readLine read . 如果线程被阻塞读取,唯一的方法就是提供一些实际数据或关闭套接字(中断线程可能会起作用,但实际上不会)。

    所以最明显的解决办法是有两个线程。一个读取原始数据,并将保持封锁。第二个是线程调用 readLine

    有很多变化。您可以使用NIO创建第一个线程,在所有使用者之间共享一个线程实例。

    或者你可以写一个 Selector.wakeup 存在并工作。

        3
  •  9
  •   frIT    8 年前

    抱歉迟到了6年多;-)我需要一些可中断的readLine,当我从键盘上阅读时,一个简单的业余爱好控制台应用程序。换句话说,我不能“关闭插座”。

    System.in InputStream 这显然已经做了一些缓冲(你需要按 输入 ]). 然而,似乎有人建议用一个 BufferedReader

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

    另一个可能会发现的是 BufferedReader.readLine() 阻塞,直到提供输入(即使线程被中断,似乎只结束线程一次) readline() 获取其输入)。然而,可以预测何时 BufferedReader.read() 不阻止 ,通过呼叫 BufferedReader.ready() == true == false 不保证

    因此,我将上述思想结合到一个方法中,该方法可以读取 一个字符接一个字符,如果线程被中断,则在每个字符之间签入,并检查行尾,此时返回文本行。

    consoleIn 如上所述的变量。(批评也可能受到欢迎……):

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

    ... 在调用它的线程中,捕获异常并适当地结束线程。

    这是用java8在Linux上测试的。

        4
  •  8
  •   AdrieanKhisbe aytigra    11 年前

    最终我发现打电话是可能的 socket.shutdownInput() 在中断线程中,毫无例外地退出readLine调用。我在SIGINT处理程序中进行此调用,以便清理并关闭主线程中的套接字。

    请注意,outputstream具有 socket.shutdownOutput()

        5
  •  0
  •   mhshams    14 年前

        6
  •  0
  •   Cord Rehn    8 年前

    read 方法直到 BufferedReader

    public String readLineTimeout(BufferedReader reader, long timeout) throws TimeoutException, IOException {
        long start = System.currentTimeMillis();
    
        while (!reader.ready()) {
            if (System.currentTimeMillis() - start >= timeout)
                throw new TimeoutException();
    
            // optional delay between polling
            try { Thread.sleep(50); } catch (Exception ignore) {}
        }
    
        return reader.readLine(); // won't block since reader is ready
    }
    
        7
  •  0
  •   scopchanov    6 年前

    如果你想用 readLine 例如,在客户机-服务器tcp体系结构中的服务器套接字上,可以使用 setSoTimeout(int timeout) 属于 java.net.Socket

    Socket#setSoTimeout(int timeout) Documentation

    使用指定的超时启用/禁用SO\U超时(毫秒)。将此选项设置为非零超时, 对与此套接字关联的InputStream的read()调用将仅阻塞此时间量 . 如果超时过期,则 java.net.SocketTimeoutException 已引发,但套接字仍然有效。

    public class MainApp {
        public static void main(String[] args) throws Exception {
            ExecutorService executorService = Executors.newFixedThreadPool(10);
            ServerSocket serverSocket = new ServerSocket(11370);
            Socket clientSocket = serverSocket.accept();
            clientSocket.setSoTimeout(2000);
            executorService.execute(new ReadingThread(clientSocket));
            // ... some async operations
            executorService.shutdown();
        }
    }
    
    public class ReadingThread implements Runnable {
        private final Socket clientSocket;
        public ReadingThread(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }
    
        @Override
        public void run() {
            BufferedReader socketReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            String readInput = null;
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    readInput = socketReader.readLine();
                } catch (SocketTimeoutException e) {
                    continue; 
                }
            }
            // operations with readInput
        }
    }
    

    主应用程序实现一个服务器套接字,该套接字侦听连接并具有线程池。如果接受了传入的客户机通信,那么将从池中分配一个新线程,并在中调用run函数 ReadingThread 在用于与客户端通信的套接字上 设置超时(int超时) 您可以在循环中检查 读取线程 已被主应用程序中断,如果是,请停止从套接字读取。

        8
  •  -1
  •   Michael    14 年前

    readLine() read()

    BufferedReader reader = //...
    int c;
    while ((c = reader.read()) != -1){
      if (Thread.isInterrupted()){
        break;
      }
      if (c == '\n'){
        //newline
      }
      //...
    }
    
        9
  •  -1
  •   A.H.    13 年前

    Foo 它在套接字端使用非阻塞NIO,但也提供了 InputStream Reader 另一端的接口。如果 BufferedReader 进入它自己的 read ,它将调用 ,它将调用 Selector.select select

    如果另一个线程想要解除读卡器的阻塞,它必须调用 Selector.wakeup 选择器可以通过抛出异常优雅地返回 缓冲区读取 .

    变体A:呼叫 Selector.select(timeout) 忙着做投票灯。