System.out.println 和 System.err.println out order

2022-08-31 17:16:13

我的和呼叫不会按照我发出的顺序打印到主机上。System.out.println()System.err.println()

public static void main(String[] args) {
    for (int i = 0; i < 5; i++) {
        System.out.println("out");
        System.err.println("err");
    }
}

这会产生:

out
out
out
out
out
err
err
err
err
err

而不是交替和 .这是为什么呢?outerr


答案 1

它们是不同的流,在不同的时间被冲洗。

如果你把

System.out.flush();
System.err.flush();

在您的循环中,它将按预期工作。

为了澄清,输出流被缓存,因此所有写入都进入此内存缓冲区。经过一段时间的安静,它们实际上被写出来了。

写入两个缓冲区,然后在一段时间不活动后,它们都被刷新(一个接一个)。


答案 2

这是由JVM中的一个功能引起的,除非你进行像Marcus A.提供的黑客攻击,否则解决起来并不容易。在这种情况下,工作原理要复杂得多,但其原因要复杂得多。.flush()

这是怎么回事?

当你用Java编程时,你不是直接告诉计算机该做什么,而是告诉JVM(Java虚拟机)你希望它做什么。它将这样做,但以更有效的方式。你的代码不是确切的详细说明,在这种情况下,你只需要一个编译器,就像C和C++,JVM把你的代码作为它应该优化的规范列表,然后做什么。这就是这里发生的事情。Java 看到您正在将字符串推送到两个不同的缓冲流中。执行此操作的最有效方法是缓冲您希望流输出的所有字符串,然后将其输出。这种情况一次发生一个流,本质上是转换你的代码做这样的事情(当心:伪代码)

for(int i = 0; i < 5; i++) {
    out.add();
    err.add();
}
out.flush();
err.flush();

因为这效率更高,所以这就是 JVM 将要执行的操作。在循环中添加将向JVM发出信号,表明需要在每个循环中进行刷新,而上述方法无法改进。但是,如果您为了解释其工作原理而省略了循环,则JVM将重新排序您的代码以最后完成打印,因为这更有效。.flush()

System.out.println("out");
System.out.flush();
System.err.println("err");
System.err.flush();
System.out.println("out");
System.out.flush();
System.err.println("err");
System.err.flush();

此代码将始终重新组织为如下所示:

System.out.println("out");*
System.err.println("err");*
System.out.println("out");*
System.err.println("err");*
System.out.flush();
System.err.flush();

因为缓冲许多缓冲区只是为了在之后立即刷新它们,比缓冲所有要缓冲的代码然后同时刷新它们需要花费更多的时间。

如何解决

这就是代码设计和架构可能发挥作用的地方;你有点不解决这个问题。要解决此问题,您必须使缓冲打印/刷新,缓冲打印/刷新比缓冲区所有然后刷新更有效。这很可能会引诱你进入糟糕的设计。如果如何有序地输出它对你来说很重要,我建议你尝试一种不同的方法。For循环是破解它的一种方法,但你仍然在破解JVM的功能,为你重新排列和优化你的代码。.flush()

*我无法验证您首先添加到的缓冲区是否始终会首先打印,但它很可能会打印。


推荐