Sincronización y System.out.println

Si hay varios subprocesos que llaman a System.out.println (String) sin sincronización, ¿se puede intercalar el resultado? La API no hace mención de la sincronización, por lo que parece posible, o ¿se evita la salida entrelazada mediante el almacenamiento en búfer y / o el modelo de memoria de VM, etc.?

EDITAR:

Por ejemplo, si cada hilo contiene:

System.out.println("ABC"); 

es la salida garantizada para ser:

 ABC ABC 

o podría ser:

 AABC BC 

Como la documentación de API no menciona la seguridad de subprocesos en el objeto System.out ni el PrintStream#println(String) , no puede suponer que es seguro para subprocesos .

Sin embargo, es muy posible que la implementación subyacente de una JVM particular utilice una función de seguridad de subprocesos para el método println (por ejemplo, printf en glibc ) para que, en realidad, la salida se garantice según su primer ejemplo (siempre ABC\n entonces ABC\n , nunca intercalados caracteres por su segundo ejemplo). Pero tenga en cuenta que hay muchas implementaciones de JVM y solo se les exige cumplir con la especificación JVM, no con las convenciones fuera de esa especificación.

Si debe asegurarse de que no se intercalarán las llamadas println como describe, debe aplicar la exclusión mutua manualmente, por ejemplo:

 public void safePrintln(String s) { synchronized (System.out) { System.out.println(s); } } 

Por supuesto, este ejemplo es solo una ilustración y no debe tomarse como una “solución”; hay muchos otros factores a considerar. Por ejemplo, el safePrintln(...) anterior solo es seguro si todo el código usa ese método y nada llama a System.out.println(...) directamente.

El código fuente de OpenJDK responde a su pregunta:

 public void println(String x) { synchronized (this) { print(x); newLine(); } } 

Referencia: http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/39e8fe7a0af1/src/share/classes/java/io/PrintStream.java

Siempre y cuando no cambie el OutputStream través de System.setOut , es seguro para subprocesos.

Aunque es seguro para subprocesos, puede tener muchos subprocesos escribiendo en System.out tal que

 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"); 

puedo leer

 1 2 A 3 B C 

entre otras combinaciones.

Entonces para responder a tu pregunta:

Cuando escribe en System.out , adquiere un locking en la instancia de OutputStream , luego escribe en el búfer y se vacía inmediatamente.

Una vez que libera el locking, el OutputStream se vacía y se escribe en. No habría una instancia en la que tendrías diferentes cadenas unidas como 1A 2B .

Editar para responder a su edición:

Eso no sucedería con System.out.println . Como PrintStream sincroniza toda la función, llenará el búfer y luego lo descargará atómicamente. Cualquier nuevo hilo que ingrese ahora tendrá un nuevo buffer para trabajar.

Solo para aclarar, digamos que tiene dos hilos, uno que imprime "ABC" y otro que imprime "DEF" . Nunca obtendrás una salida como esta: ADBECF , pero podrías obtener cualquiera

 ABC DEF 

o

 DEF ABC