8

VM Java 控制台输出的一个常见问题是 System.out 和 System.err 通常不能正确同步,可能是因为它们位于不同的线程上。这会导致混合输出,如下所示:

调试输出与运行时异常堆栈跟踪混合

[8, 1, 3, 5, 9, 13, 15, 17, 19]
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 9
scanning xAnswer: 1 xValue: 1 total: 1 [1, 1, 0, 0, 0, 0, 0, 0, 0]
    at cra.common.Group_jsc.listSubsetSum(Group_jsc.java:29)
scanning xAnswer: 2 xValue: 2 total: 4 [2, 1, 2, 0, 0, 0, 0, 0, 0]
    at cra.common.Group_jsc.main(Group_jsc.java:12)
scanning xAnswer: 3 xValue: 3 total: 9 [3, 1, 2, 3, 0, 0, 0, 0, 0]
scanning xAnswer: 4 xValue: 4 total: 18 [4, 1, 2, 3, 4, 0, 0, 0, 0]
scanning xAnswer: 5 xValue: 5 total: 31 [5, 1, 2, 3, 4, 5, 0, 0, 0]
  reset to xAnswer: 4 xValue: 5 total: 26 [4, 1, 2, 3, 5, 5, 0, 0, 0]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
scanning xAnswer: 5 xValue: 6 total: 41 [5, 1, 2, 3, 5, 6, 0, 0, 0]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  reset to xAnswer: 4 xValue: 6 total: 35 [4, 1, 2, 3, 6, 6, 0, 0, 0]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
scanning xAnswer: 5 xValue: 7 total: 52 [5, 1, 2, 3, 6, 7, 0, 0, 0]
  reset to xAnswer: 4 xValue: 7 total: 45 [4, 1, 2, 3, 7, 7, 0, 0, 0]
scanning xAnswer: 5 xValue: 8 total: 64 [5, 1, 2, 3, 7, 8, 0, 0, 0]
  reset to xAnswer: 4 xValue: 8 total: 56 [4, 1, 2, 3, 8, 8, 0, 0, 0]

Process finished with exit code 1

由于异常发生在进程结束时,我希望异常的打印输出发生在程序中的所有 println之后。为什么会发生这种情况以及可以采取哪些措施来纠正问题?

(请注意,这个特定示例来自 IntelliJ 的 IDEA 控制台,但在 Eclipse 和其他 Java IDE 中也会发生同样的事情)

4

3 回答 3

2

VM Java 控制台输出的一个常见问题是 System.out 和 System.err 通常不能正确同步,

不,它们完美同步。问题是这些是混合的,因为它们被打印为单独调用println(...). 这是来自的代码Exception.printStackTrace()

        StackTraceElement[] trace = getOurStackTrace();
        for (int i=0; i < trace.length; i++)
            s.println("\tat " + trace[i]);

记录器(如 log4j)获取完整的堆栈跟踪并将多行转换为单个日志输出调用,然后以原子方式持久化。

为什么会发生这种情况以及可以采取哪些措施来纠正问题?

通常对于 Unix 程序,标准输出被缓冲,而标准错误则没有。我不认为 Java 是这样的,但也许是这样。要阅读的 javadocs System.out

“标准”输出流。此流已经打开并准备好接受输出数据。通常,此流对应于主机环境或用户指定的显示输出或另一个输出目的地。

相对于System.err

按照惯例,此输出流用于显示错误消息或其他应立即引起用户注意的信息,即使主要输出流(变量的值out)已被重定向到文件或其他通常在没有持续监控。

有关更多详细信息,请参阅此答案:为什么有时会先打印 System.err 语句?

如果这从命令行运行,您应该将 out 和 err 输出重定向到不同的文件。以下是使用 ~unix 的方法:

如何将stderr和stdout重定向到同一行bash中的不同文件?

在 Java 中,您可以使用System.setOut(...)andSystem.setErr(...)将不同的输出发送到不同PrintStream的 s,这样行就不会交错。


您编辑了问题以注意这是在 IDE 内部发生的。如果您需要使用System.outerr然后您可以使用上面的 Java 代码重定向它们。

但是,通常使用日志记录代码。常见的日志记录包是log4jlogback,它们以原子方式将单个多行日志消息写入输出文件,因此它们不会交错。正如@fge 所提到的,尽管其他软件包提供了更多功能,但 JVM 也java.util.logging内置了。

于 2013-06-14T18:14:14.120 回答
0

为什么会发生这种情况以及可以采取哪些措施来纠正问题?

因为 syserr 和 sysout 是单独的数据流,但系统 (IDE) 控制台正试图同时显示两者。这可以通过使用Logger通常正确排序日志中的条目来解决。

另一种可能性是调用System.setErr并将其分配给PrintStream错误日志文件。这将是重定向错误流的 Java 等效解决方案。

于 2013-06-14T18:17:58.490 回答
0

PyCharm 也有这个问题,我相信它使用相同的 IDE 引擎。如果您将以下行添加到idea.properties文件中,则可以解决此问题:

output.reader.blocking.mode=true

通过idea.properties帮助 | 编辑自定义属性。

于 2019-03-07T06:46:30.803 回答