如果多个线程在不同步的情况下调用 System.out.println (String) ,输出是否可以交叉?或者每行的写是原子的?空气污染指数没有提到同步,因此这似乎是可能的,或者是交织输出被缓冲和/或 VM 内存模型等阻止。?
编辑:
例如,如果每个线程包含:
System.out.println("ABC");
保证的输出是:
ABC ABC
或者可能是:
AABC BC
只要你不改变通过 System.setOut的 OutputStream是线程安全的。
System.setOut
OutputStream
虽然它是线程安全的,但是可以有许多线程写入 System.out,以便
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
among other combinations.
回答你的问题:
When you write to System.out – it acquires a lock on the OutputStream instance - it will then write to the buffer and immediately flush.
一旦它释放锁,OutputStream就被刷新并写入。不会出现像 1A 2B那样有不同字符串联接的实例。
1A 2B
编辑回答你的编辑:
System.out.println不会发生这种情况。由于 PrintStream同步整个函数,它将填充缓冲区,然后自动刷新它。任何进入的新线程现在都将有一个新的缓冲区可以使用。
System.out.println
PrintStream
因为 API 文档没有提到 System.out物体上的线程安全性,也没有提到 PrintStream#println(String)方法 不能假设它是线程安全的。
PrintStream#println(String)
然而,一个特定 JVM 的底层实现完全有可能为 println方法使用一个线程安全的函数(例如 printf在 glibc 频道) ,因此,实际上,每个第一个示例的输出都是有保证的(总是 ABC\n然后是 ABC\n,从不在第二个示例中间插入字符)。但是请记住,有许多 JVM 实现,它们只需要遵守 JVM 规范,而不需要遵守规范之外的任何约定。
println
printf
ABC\n
如果你的 绝对必须确保没有像你描述的那样散布 println 调用,那么你必须手动执行互斥锁,例如:
public void safePrintln(String s) { synchronized (System.out) { System.out.println(s); } }
当然,这个例子只是一个例子,不应该被视为一个“解决方案”; 还有许多其他因素需要考虑。例如,上面的 safePrintln(...)方法只有在 所有代码使用该方法并且没有任何东西直接调用 System.out.println(...)时才是安全的。
safePrintln(...)
System.out.println(...)
澄清一下,假设您有两个线程,一个打印 "ABC",另一个打印 "DEF"。您永远不会得到这样的输出: ADBECF,但是您可以得到任何一个
"ABC"
"DEF"
ADBECF
ABC DEF
或者
DEF ABC
The OpenJDK source code answers your question:
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