java - 我怎样才能在 stdout/stderr 准备就绪时进行回调而不是忙于轮询?

标签 java android process io

我发现所有关于从 Process stdout 读取的讨论都是以阻塞方式进行的,如下所示:

Process process=Runtime.getRuntime().exec(cmd);
BufferedReader in=new BufferedReader(
    new InputStreamReader(process.getInputStream()));
for(String line;(line=in.readLine())!=null;)
{
    useText(line);
}

如果我试图避免阻塞,我的选择是使用 in.ready() 轮询流。

但我真正需要的是让进程继续运行并做一些有用的事情,并且只在数据实际可用时才尝试读取任何内容。所以我正在寻找类似 Qt 的 QProcess::readyReadStandardOutput 信号的东西。请注意,BufferedReader 的方法ready 不是我要找的:它只是一种我必须反复检查的方法,而不是任何类型的信号。

Java 中有类似的东西吗?

最佳答案

如果你有一个事件循环,你可以启动一个后台线程来向那个事件循环添加事件。

例如

ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true); // capture errors as well.
Process process = pb.start();
BufferedReader in = new BufferedReader(
        new InputStreamReader(process.getInputStream()));
Thread t = new Thread(() -> {
    try {
        for (String line; (line = in.readLine()) != null; ) {
            Activity.runOnUiThread(() -> useText(line));
        }
    } catch (Exception e) {
        logger.log(e);
    } finally {
        Activity.runOnUiThread(() -> noMoreText());
    }
});
t.setDaemon(true);
t.start();

你可以有一个线程只执行 queue.add(in.readLine()) 然后你的主线程可以轮询这个队列。这样所有多线程问题都变得简单且包含在内。

static final String EOF = new String(); // use for == comparison later

ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true); // capture errors as well.
Process process = pb.start();
BufferedReader in = new BufferedReader(
        new InputStreamReader(process.getInputStream()));
int capacity = 1024;
BlockingQueue<String> lines = new ArrayBlockingQueue<>(capacity);
Thread t = new Thread(() -> {
    try {
        for (String line; (line = in.readLine()) != null; ) {
            lines.add(line);
            while (lines.remainingCapacity() < 2) // don't run out of memory if too much.
                Thread.sleep(50);
        }
    } catch (Exception e) {
        logger.log(e);
    } finally {
        lines.offer(EOF);
    }
});
t.setDaemon(true);
t.start();

// later in a loop
String line = lines.poll();
if (line == null) // no data yet.

else if (line == EOF) // we have the EOF marker.

关于java - 我怎样才能在 stdout/stderr 准备就绪时进行回调而不是忙于轮询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53113901/

相关文章:

java - 动态创建变量,java变量的数据类型

java - 在 MultipleOutputs 中 - 避免将我的 key 写入文件

java - 如何操作 JSON 树的叶子

php - 检索特定的数据行

c++ - 为什么 OSX 事件监视器不显示我启动的进程?

c - 这个程序创建了多少个进程,它们是由哪些进程创建的?

java - 为什么 Fortify SCA 针对我的项目中不再存在的文件报告问题?

android - 听相机 Action

Python:重新格式化一组文本文件的简洁/优雅的方式?

android - 如何在 ActionBar 中添加编辑文本字段和按钮?