複数のスレッドが同期せずにSystem.out.println(String)を呼び出す場合、出力はインターリーブできますか?または、各行の書き込みはアトミックですか? [〜#〜] api [〜#〜] は同期について言及していないため、これは可能と思われるか、バッファリングおよび/またはVM =メモリモデルなど?
編集:
たとえば、各スレッドに次が含まれている場合:
System.out.println("ABC");
出力が保証される出力は次のとおりです。
ABC
ABC
またはそれは次のようになります:
AABC
BC
APIドキュメントでは _System.out
_オブジェクト のスレッドセーフについて言及していないため、 PrintStream#println(String)
methodスレッドセーフであると想定することはできません。
ただし、特定のJVMの基礎となる実装がprintln
メソッドにスレッドセーフ関数を使用することは完全に可能です(たとえば、glibcの printf
)。実際には、出力は最初の例ごとに保証されます(常に_ABC\n
_、次に_ABC\n
_、2番目の例ごとに文字が散在することはありません)。ただし、JVMの実装は多数あり、JVM仕様に準拠することのみが必要であり、その仕様以外の規則には準拠しないことに注意してください。
絶対にを保証する必要がある場合、説明のとおりprintln呼び出しが散在しないようにする場合は、相互排除を手動で強制する必要があります。次に例を示します。
_public void safePrintln(String s) {
synchronized (System.out) {
System.out.println(s);
}
}
_
もちろん、この例は単なる例であり、「解決策」として解釈されるべきではありません。考慮すべき他の多くの要因があります。たとえば、上記のsafePrintln(...)
メソッドは、allコードがそのメソッドを使用し、System.out.println(...)
を呼び出さない場合にのみ安全です。直接。
OpenJDKソースコードはあなたの質問に答えます:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
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
は関数全体を同期するため、バッファをいっぱいにしてからアトミックにフラッシュします。入ってくる新しいスレッドには、作業するための新しいバッファがあります。
明確にするために、2つのスレッドがあるとします。1つは"ABC"
を出力し、もう1つは"DEF"
を出力します。次のような出力は決して得られません:ADBECF
、しかしどちらかを得ることができます
ABC
DEF
または
DEF
ABC