来自 System.out.println 的多线程输出是否交错



如果多个线程调用System.out.println(String(而不同步,输出可以交错吗?还是每行的写入都是原子的?API 没有提到同步,所以这似乎是可能的,还是通过缓冲和/或 VM 内存模型等阻止了交错输出?

编辑:

例如,如果每个线程包含:

System.out.println("ABC");

输出是否保证为:

ABC
ABC

或者可能是:

AABC
BC

由于 API 文档没有提到 System.out 对象的线程安全性,PrintStream#println(String)方法也没有提到,因此您不能假设它是线程安全的

但是,特定 JVM 的底层实现完全有可能对 println 方法使用线程安全函数(例如 printf在 glibc 上(,因此,实际上,每个示例的输出将得到保证(始终ABCn然后ABCn,每个示例永远不会穿插字符(。 但请记住,有很多 JVM 实现,它们只需要遵守 JVM 规范,而不是该规范之外的任何约定。

如果您绝对必须确保没有 println 调用会像您描述的那样穿插,那么您必须手动强制执行互斥,例如:

public void safePrintln(String s) {
  synchronized (System.out) {
    System.out.println(s);
  }
}

当然,这个例子只是一个例证,不应该作为一个"解决方案";还有许多其他因素需要考虑。例如,上面的 safePrintln(...) 方法只有在所有代码都使用该方法并且没有直接调用System.out.println(...)时才是安全的。

OpenJDK源代码回答了你的问题:

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

参考: http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/39e8fe7a0af1/src/share/classes/java/io/PrintStream.java

只要您不通过System.setOut更改OutputStream,它就是线程安全的。

虽然它是线程安全的,但您可以让许多线程写入System.out这样

Thread-1
  System.out.println("A");
  System.out.println("B");
  System.out.println("C");
Thread-2
  System.out.println("1");
  System.out.println("2");
  System.out.println("3");

可以阅读

1
2
A
3
B
C

以及其他组合。

所以回答你的问题:

当您写入System.out时 - 它会在OutputStream实例上获取锁 - 然后它将写入缓冲区并立即刷新。

释放锁后,OutputStream将被刷新并写入。 不会有像1A 2B那样连接不同字符串的实例。

编辑

以回答您的编辑:

这不会发生在System.out.println.由于PrintStream同步整个函数,它将填充缓冲区,然后以原子方式刷新它。任何传入的新线程现在都将有一个新的缓冲区可供使用。

澄清一下,假设您有两个线程,一个用于打印"ABC",另一个用于打印"DEF"。你永远不会得到这样的输出:ADBECF,但你可以得到

ABC
DEF 

DEF
ABC

相关内容

  • 没有找到相关文章

最新更新