When to Call System.out.flush() in Java? – 在 Java 中何时调用 System.out.flush()?

最后修改: 2023年 9月 13日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.导言

The System.out stream is the fundamental feature of Java language, which is commonly used for producing console outputs. Whether using it to print our first “Hello, World!” or debug complex applications, we’ll likely encounter System.out.

System.out 流是 Java 语言的基本特性,通常用于生成控制台输出。无论是使用它来打印第一句 “Hello, World!”,还是调试复杂的应用程序,我们都可能会遇到 System.out

In this tutorial, we’ll discuss when to call System.out.flush() in Java.

在本教程中,我们将讨论在 Java 中何时调用 System.out.flush()

2. Buffering Concept

2.缓冲概念

Buffering is a fundamental concept in computing, especially regarding I/O operations. In the context of output streams, buffering refers to the temporary data storage before it’s written out. Once this buffer reaches its capacity or is explicitly flushed, the accumulated data is written out in a single go.

缓冲是计算中的一个基本概念,尤其是在I/O操作中。在输出流的上下文中,缓冲指的是写出数据前的临时数据存储。一旦缓冲区达到其容量或被显式刷新,累积的数据将一次性写出。

However, this buffering mechanism can sometimes lead to unexpected behavior. Data might not appear immediately where expected, leading to potential confusion. This is where understanding the role of the flush() method becomes crucial, ensuring that buffered data is written out when necessary.

不过,这种缓冲机制有时会导致意外行为。数据可能不会立即出现在预期的位置,从而导致潜在的混乱。此时,理解 flush() 方法的作用就变得至关重要,它可确保在必要时写出缓冲数据。

3. The Basics of Flushing in Java

3.Java 中刷新的基础知识

While buffering provides an efficient way to handle data, there comes a time when the buffered data needs to be sent to its intended destination immediately, regardless of whether the buffer is full. This action is known as flushing.

虽然缓冲提供了一种高效的数据处理方式,但有时缓冲数据需要立即发送到预定目的地,无论缓冲区是否已满。这种操作被称为刷新。

Not seeing the expected output immediately can be confusing when dealing with output streams. This delay is often due to the buffered data not yet being written to its destination. Flushing ensures that any data currently in the buffer is immediately written out, giving developers a real-time view of their outputs:

在处理输出流时,如果不能立即看到预期的输出,可能会令人困惑。这种延迟通常是由于缓冲数据尚未写入目的地。刷新可确保立即写出当前缓冲区中的任何数据,从而让开发人员实时查看输出:

Buffer Diagram

Java provides a built-in mechanism to explicitly flush output streams, namely the flush() method. This method is part of the OutputStream class and its subclasses, including the type behind System.out. When invoked, the flush() method ensures that any buffered data in the stream is immediately written out:

Java 提供了显式刷新输出流的内置机制,即 flush() 方法。该方法是 OutputStream 类及其子类(包括 System.out 背后的类型)的一部分。调用 flush() 方法时,可确保立即写出流中的任何缓冲数据:

public void flush() {
    if (lock != null) {
        lock.lock();
        try {
            implFlush();
        } finally {
            lock.unlock();
        }
    } else {
        synchronized (this) {
            implFlush();
        }
    }
}

4. Flushing with System.out

4.使用 System.out 进行冲洗

The behavior of System.out is determined by the JVM’s specific implementation. In many scenarios, the underlying PrintStream is configured with autoFlush enabled. This automatic flushing is why developers often don’t need to invoke the flush operation explicitly.

System.out 的行为由 JVM 的具体实现决定。在许多情况下,底层 PrintStream 配置为启用 autoFlush。这种自动刷新功能就是开发人员通常不需要显式调用刷新操作的原因。

Most of the writing methods have some checks for autoflush. They might be different, but we can see the general idea in PrintStream.implWriteln():

大多数写入方法都会对 autoflush 进行一些检查。它们可能有所不同,但我们可以在 PrintStream.implWriteln() 中看到大致的思路:</em

private void implWriteln(char[] buf) throws IOException {
    ensureOpen();
    textOut.write(buf);
    textOut.newLine();
    textOut.flushBuffer();
    charOut.flushBuffer();
    if (autoFlush)
        out.flush();
}

However, it’s worth noting that certain JVM implementations or frameworks might offer custom implementations of System.out. For instance, JUnit might disable autoFlush to optimize the display of test output.

不过,值得注意的是,某些 JVM 实现或框架可能会提供 System.out 的自定义实现。例如,JUnit 可能会禁用 autoFlush 以优化测试输出的显示。

While some sources discuss the differences between the print and println methods in relation to flushing, a closer look at the PrintStream implementation reveals no distinct behavior between the two in terms of automatic flushing. However, as mentioned previously, we should examine the actual implementation of the System.out to be sure of its behavior.

虽然一些资料讨论了 printprintln 方法在刷新方面的区别,但仔细查看 PrintStream 的实现后会发现,两者在自动刷新方面没有明显的行为。

5. Conclusion

5.结论

For many developers, System.out functions seamlessly without the need to delve into its underlying mechanics or the intricacies of flushing behavior. It’s important to remember, however, that the behavior of System.out is contingent upon the platform’s specific implementation, which can introduce variations.

对于许多开发人员来说,System.out 可以无缝运行,无需深入研究其底层机制或复杂的刷新行为。不过,重要的是要记住,System.out 的行为取决于平台的具体实现,而平台的具体实现可能会带来一些变化。

While basic applications, like the quintessential “Hello, World”, remain unaffected by buffering and flushing nuances, the story changes when we venture into more complex domains. In contexts such as advanced logging or testing frameworks, tampering with the default implementation or overusing explicit flush operations can have performance implications. It’s always prudent to strike a balance, ensuring the application’s performance remains optimal while achieving the desired output behavior.

虽然基本应用程序(如最典型的 “Hello, World”)不会受到缓冲和刷新细微差别的影响,但当我们涉足更复杂的领域时,情况就会发生变化。在高级日志记录或测试框架等情况下,篡改默认实现或过度使用显式刷新操作可能会影响性能。谨慎的做法始终是取得平衡,确保应用程序的性能保持最佳,同时实现所需的输出行为。