Синхронизация и система.из.код println


Если система вызова нескольких потоков.из.println (строка) без синхронизации, может ли выход перемежаться? Элемент API не упоминает о синхронизации, поэтому это кажется возможным или перемежается выводом, предотвращенным буферизацией и/или моделью памяти виртуальной машины и т. д.?

EDIT:

например, если каждый поток содержит:

System.out.println("ABC");

выход гарантированно будет:

ABC
ABC

или это:

AABC
BC
4 60

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();
    }
}

Ссылка: http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/39e8fe7a0af1/src/share/classes/java/io/PrintStream.java

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

просто чтобы уточнить, скажем, у вас есть две нити, одна из которых печатает "ABC" и еще одна, которая выводит "DEF". Вы никогда не получите такой результат:ADBECF, но вы могли бы получить либо

ABC
DEF 

или

DEF
ABC