java - Sincronización y System.out.println
multithreading synchronization (4)
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 bloqueo en la instancia de OutputStream
, luego escribe en el búfer y se vacía inmediatamente.
Una vez que libera el bloqueo, 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