Подтвердить что ты не робот

Чередуется ли многопоточный вывод из System.out.println

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

РЕДАКТИРОВАТЬ:

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

System.out.println("ABC");

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

ABC
ABC

или это может быть:

AABC
BC
4b9b3361

Ответ 1

Поскольку в документации API нет упоминания о безопасности потоков на System.out object, а также PrintStream#println(String) method, вы не можете предположить, что это поточно-безопасный.

Однако вполне возможно, что базовая реализация конкретной 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(...).

Ответ 3

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

Ответ 4

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

ABC
DEF 

или

DEF
ABC