Синхронизация и система.из.код 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синхронизирует всю функцию, она заполнит буфер и после этого потопит его атомарно. Любой новый поток теперь будет иметь свежий буфер для работы.