当前位置: 首页 > 面试题库 >

中断BufferedReader#readLine()而不关闭InputStream

阎志义
2023-03-14
问题内容

InputStreamProcess应重视和每当用户希望看到它或不分离。附加工作正常,但分离失败。中断readLine()方法的默认答案始终是关闭流,但是在这种情况下,我将无法Process完成,否则将完成或至少无法用于将来的附件。这是读取流的方式:

BufferedReader reader = new BufferedReader(new InputStreamReader(getProcess().getInputStream()));
String line;

while ((line = reader.readLine()) != null) {
    System.out.println(line);
}

为了分离,我尝试了一些东西:

  • 关闭任何流,失败:close方法被阻塞并等待readLine()
  • 实现另一个流,以发送空值/中止值SequenceInputStream,失败:当一个InputStream人等待输入时,另一个甚至没有被调用
  • 使用反射来解锁read()任何流中的方法,但失败了:不确定为什么,但是没有用。 我们应该继续尝试吗? 这是源代码:

    try {
    
    Field modifiers = Field.class.getDeclaredField("modifiers");
    modifiers.setAccessible(true);
    
    Field fdecoder = stream.getClass().getDeclaredField("sd");
    fdecoder.setAccessible(true);
    modifiers.setInt(fdecoder, 1);
    StreamDecoder decoder = (StreamDecoder) fdecoder.get(stream);
    
    Field flock = decoder.getClass().getSuperclass().getDeclaredField("lock");
    flock.setAccessible(true);
    modifiers.setInt(flock, 1);
    Object lock = (Object) flock.get(decoder);
    
    synchronized (lock) {
        lock.notifyAll();
    }
    

    } catch (NoSuchFieldException | IllegalAccessException e) {
    Wrapper.handleException(Thread.currentThread(), e);
    }

不知道该如何解决。您能否帮助我在readLine()不关闭流的情况下中断方法,简单而高效?谢谢。

编辑: “表现”是什么意思?我的应用程序用户不多,但是进程很多。@EJP的答案没有错-
但是对于我的应用程序来说效果不佳。我无法为数百个进程提供数百个线程,但是我可以拥有与用户观看一样多的进程。这就是为什么我尝试优雅地中断该过程。线程更少,运行/阻塞线程更少。这是描述的应用程序(https://imgur.com/VUcYUfi.png)将信息发送给用户的线程与读取输入的线程相同。


问题答案:

我没想到它会起作用,但是期货实际上是可以取消的(但是为什么呢?)。@Tarun
Lalwani提到Google的Guava库的TimeLimiter之后,我检查了一下代码,在示例中进行了尝试(可行!)并将其重写一下-
使它不是基于时间的,而是基于方法调用的?

这是我从研究中得到的结果:的包装器BufferedReader

public class CancelableReader extends BufferedReader {

    private final ExecutorService executor;
    private Future future;

    public CancelableReader(Reader in) {
        super(in);
        executor = Executors.newSingleThreadExecutor();
    }

    @Override
    public String readLine() {

        future = executor.submit(super::readLine);

        try {
            return (String) future.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } catch (CancellationException e) {
            return null;
        }

        return null;

    }

    public void cancelRead() {
        future.cancel(true);
    }

}

class使您可以BufferedReader#readLine()在需要时使用,并在想要继续/中断Thread其运行时取消它。以下是一些实际的示例代码:

public static void main(String[] args) {

    System.out.println("START");

    CancelableReader reader = new CancelableReader(new InputStreamReader(System.in));
    String line;

    new Thread(() -> {

        try {

            Thread.sleep(10000);
            reader.cancelRead();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }).start();

    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }

    System.out.println("END");

}

和它的输出:

START
> Hello World!
Hello World!
> What's up?
What's up?
END //Exactly after 5 seconds, when the cancel was called
> Hey, you still there?
//No output as expected

我要说的最后一件事是 为什么这样做而不关闭InputStream或为每个进程创建一个线程?
在这种情况下,InputStream是的流Process,这意味着我们无法将其关闭。一种方法是取消阻塞readLine()返回null以完成while-loop,但这是通过进行的Reflection,它现在不如我们的解决方案那么漂亮,并且由于任何原因均无法正常工作。该应用程序使用许多进程,但用户数量有限-
这就是为什么我们决定每个用户而不是每个进程确定线程数量的原因。

我希望你们将来会发现这个主题,对您有帮助。如果您留下支持,那将很棒,所以我可以找回我的赏金代表。



 类似资料:
  • 问题内容: 我试图在多个线程中逐行读取套接字的输入。如何中断,以便可以正常停止正在阻塞的线程? 编辑(赏金) :可以在不关闭套接字的情况下完成此操作吗? 问题答案: 关闭中断线程上的套接字。这将导致在中断的线程上引发异常。 有关此和其他并发问题的更多信息,我强烈推荐Brian Goetz的书“ Java并发实践”。

  • 问题内容: 我注意到,如果关闭,我将无法再从键盘插入输入,因为已经关闭了。无论如何,我可以保留(删除文件时需要它),然后从键盘添加更多输入吗? 问题答案: 看起来您需要: http://commons.apache.org/io/apidocs/org/apache/commons/io/input/CloseShieldInputStream.html 在制作读者之前,先将System.in环绕

  • 问题内容: 我正在使用从远程服务器读取响应的方法(该服务器使用C语言编写,并且无法访问源代码)。 但是它总是在最后一行阻塞,直到超时为止。所以我用下面的代码: 我发现读取的最后一个字节的整数值为13,我认为这是回车,对吗? 那么为什么该方法会阻塞?服务器通常如何发出信号通知流结束?谢谢。 问题答案: 在网络连接的情况下,当套接字关闭时,流终止。 因此阻塞直到收到“行尾”或您手动关闭连接是完全正常的

  • 问题内容: 我试图将我的应用程序中较大且经常使用的部分重构为单独的方法,以使其易于维护。 其中一些方法要求用户输入并进行输入验证,因此我使用了Scanner和System.in,但是当我关闭Scanner时,我也关闭了System.in。 所以我的问题是,我只能通过用CloseShieldInputStream屏蔽System.in来防止System.in关闭,还是应该开始将Scanner传递给方

  • 我试图将应用程序中大量且经常使用的部分重新划分为不同的方法,以使其更容易维护。 其中一些方法要求用户输入并进行输入验证,因此我使用了扫描仪和系统。但当我关闭扫描仪时,我也会关闭系统。在里面 所以我的问题是,我只能阻止系统。通过使用CloseShieldInputStream屏蔽它来关闭,还是我应该开始向方法传递一个扫描器?

  • 我有以下代码: 在过程中的某个时候,它会冻结并且不前进。它不会向readLine()方法返回任何内容,并且会陷入等待不返回的内容。我如何管理这种等待?谢谢