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

Fel*_*ler 10 java process stream

InputStream我的Process应该安装和拆卸每当用户希望看到这一点.附着工作正常,但分离失败.中断该readLine()方法的默认答案始终是关闭流,但我不能在这种情况下或Process将完成或至少不可用于将来的附件.这是流的读取方式:

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

while ((line = reader.readLine()) != null) {
    System.out.println(line);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 关闭任何流,失败:close方法阻塞并等待readLine()
  • 实现另一个流来发送null/abortion值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);
    }
    
    Run Code Online (Sandbox Code Playgroud)

不知道如何解决这个问题.你可以帮我打断readLine()方法而不关闭流,简单而高效吗?谢谢.

编辑: "高性能"是什么意思?我的应用程序用户不多,但有很多进程.@EJP的答案并没有错 - 但在我的应用程序中无法满足要求.我无法为数百个进程提供数百个线程,但我可以拥有与用户观看的一样多的进程.这就是为什么我试图优雅地中断这个过程.线程更少,线程运行/阻塞更少.以下是描述的应用程序(https://imgur.com/VUcYUfi.png)向用户发送信息的线程与读取输入的线程相同.

Fel*_*ler 6

我没想到它会起作用,但期货实际上是可以取消的(但为什么呢?).之后@Tarun Lalwani提到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);
    }

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

它的输出:

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
Run Code Online (Sandbox Code Playgroud)

我想说的最后一件事就是为什么这个并没有关闭InputStream或者每个进程创建一个Thread? 在这种情况下,InputStream是a的流Process,这意味着我们无法关闭它.一种方法是取消阻止readLine()并返回null来完成while-loop,但这是用的Reflection,这不像我们现在的解决方案那么漂亮,并且因任何原因都不起作用.该应用程序使用许多进程,但用户数量有限 - 这就是为什么我们决定每个用户而不是每个进程的线程数量.

我希望你们将来会找到这个主题,它对你有所帮助.如果你留下一个upvote会很棒,所以我可以取回我的奖金代表.不要忘记赞成评论!他们帮了我很多,并把我带到了正确的解决方案: 中断BufferedReader#readLine()而不关闭InputStream