Синхронизация и система.из.код println
Если система вызова нескольких потоков.из.println (строка) без синхронизации, может ли выход перемежаться? Элемент API не упоминает о синхронизации, поэтому это кажется возможным или перемежается выводом, предотвращенным буферизацией и/или моделью памяти виртуальной машины и т. д.?
EDIT:
например, если каждый поток содержит:
System.out.println("ABC");
выход гарантированно будет:
ABC
ABC
или это:
AABC
BC
4 ответа:
поскольку в документации API не упоминается потокобезопасность на
System.out
объект иPrintStream#println(String)
методвы не можете предположить, что это является потокобезопасным.однако вполне возможно, что базовая реализация конкретной JVM использует потокобезопасную функцию для
println
способ (например,printf
в glibc) так что, в действительности, выход будет гарантирован в вашем первом примере (всегдаABC\n
затемABC\n
, никогда не перемежаются символы в вашем втором примере). Но имейте в виду, что существует множество реализаций 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(); } }
до тех пор, пока вы не измените
OutputStream
черезSystem.setOut
это потокобезопасными.хотя это потокобезопасно вы можете иметь много потоков записи в
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
синхронизирует всю функцию, она заполнит буфер и после этого потопит его атомарно. Любой новый поток теперь будет иметь свежий буфер для работы.