web-dev-qa-db-ja.com

System.out.printlnからのマルチスレッド出力はインターリーブされています

複数のスレッドが同期せずにSystem.out.println(String)を呼び出す場合、出力はインターリーブできますか?または、各行の書き込みはアトミックですか? [〜#〜] api [〜#〜] は同期について言及していないため、これは可能と思われるか、バッファリングおよび/またはVM =メモリモデルなど?

編集:

たとえば、各スレッドに次が含まれている場合:

System.out.println("ABC");

出力が保証される出力は次のとおりです。

ABC
ABC

またはそれは次のようになります:

AABC
BC
65
Ellen Spertus

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(...)を呼び出さない場合にのみ安全です。直接。

56
maerics

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

19
twimo

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は関数全体を同期するため、バッファをいっぱいにしてからアトミックにフラッシュします。入ってくる新しいスレッドには、作業するための新しいバッファがあります。

9
John Vint

明確にするために、2つのスレッドがあるとします。1つは"ABC"を出力し、もう1つは"DEF"を出力します。次のような出力は決して得られません:ADBECF、しかしどちらかを得ることができます

ABC
DEF 

または

DEF
ABC
2
parkovski