java - 在控制台输出中使用 println 正确排序运行时异常

标签 java multithreading debugging ide system.out

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 中)

最佳答案

A common problem with VM Java console output is that System.out and System.err are not usually synchronized properly,

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

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

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

Why is this happening and what can be done to correct the problem?

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

The "standard" output stream. This stream is already open and ready to accept output data. Typically this stream corresponds to display output or another output destination specified by the host environment or user.

System.err 对比:

By convention, this output stream is used to display error messages or other information that should come to the immediate attention of a user even if the principal output stream, the value of the variable out, has been redirected to a file or other destination that is typically not continuously monitored.

有关详细信息,请参阅此答案:Why do System.err statements get printed first sometimes?

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

How to redirect stderr and stdout to different files in the same line of bash?

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


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

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

关于java - 在控制台输出中使用 println 正确排序运行时异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17114769/

相关文章:

visual-studio-2008 - 解决方案中 "Rebuild Solution"编译成功的网站无法启动调试器

java - 从 Arraylist 实现 jTable

java - 单击 JPanel 绘制形状

java - 如何使 Maven 解析器用于 Shrinkwrap 工作?

java - Maven依赖管理: Transitive Vs Direct Dependency

multithreading - Play Framework : Async vs Sync performance

c++ - 通过 Qt 中的线程调用 Rust 库

java - waitTermination() 是否使程序 hibernate

debugging - 如何调试 Razor 页面中的嵌入式代码?

iphone - iOS 如何在没有堆栈跟踪的情况下调试崩溃,如 : [__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array?