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

时间:2018-04-04 13:59:05

标签: java process stream

只要用户想要查看,InputStream的{​​{1}}就应该附加和分离。附着工作正常,但分离失败。中断Process方法的默认答案始终是关闭流,但在这种情况下我无法完成或readLine()将完成或至少不可用于将来的附件。这是流的读取方式:

Process

要分离我尝试了一些东西:

  • 关闭所有流,失败:close方法阻塞并等待readLine()
  • 使用BufferedReader reader = new BufferedReader(new InputStreamReader(getProcess().getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } 实现另一个流来发送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); } 方法而不关闭流,简单而高效吗?感谢。

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

2 个答案:

答案 0 :(得分:5)

我没想到它会起作用,但期货实际上是可以取消的(但为什么呢?)。 在@Tarun Lalwani提到谷歌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或为每个进程创建一个Thread? 在这种情况下,InputStreamProcess的流,这意味着我们无法关闭它。一种方法是取消阻止readLine()并返回null以完成while - 循环,但这是使用Reflection进行的,这不像我们现在的解决方案那么漂亮而且没有因任何原因而工作。该应用程序使用许多进程,但用户数量有限 - 这就是为什么我们决定每个用户而不是每个进程的线程数量。

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

答案 1 :(得分:4)

你要回到前面。

您无法停止收集流程的输出,或者您将停止子流程。

当用户不想看到输出时,您希望停止显示输出。仅将其视为用户界面问题。