Si plusieurs threads appellent System.out.println (String) sans synchronisation, la sortie peut-elle être entrelacée? Ou l'écriture de chaque ligne est-elle atomique? L'API ne fait aucune mention de la synchronisation, donc cela semble possible, ou la sortie entrelacée est empêchée par la mise en mémoire tampon et/ou le VM = modèle de mémoire, etc.?
MODIFIER:
Par exemple, si chaque thread contient:
System.out.println("ABC");
est la sortie garantie d'être:
ABC
ABC
ou pourrait-il être:
AABC
BC
Étant donné que la documentation de l'API ne fait aucune mention de la sécurité des threads sur l'objet System.out
, ni la méthode PrintStream#println(String)
vous ne pouvez pas supposer qu'il est thread-safe .
Cependant, il est tout à fait possible que l'implémentation sous-jacente d'une JVM particulière utilise une fonction thread-safe pour la méthode println
(par exemple printf
sur glibc ) de sorte que, en réalité, la sortie sera garantie par votre premier exemple (toujours ABC\n
puis ABC\n
, jamais de caractères entrecoupés par votre deuxième exemple). Mais gardez à l'esprit qu'il existe de nombreuses implémentations JVM et qu'elles sont uniquement requises pour adhérer à la spécification JVM, et non à des conventions en dehors de cette spécification.
Si vous devez absolument vous assurer qu'aucun appel println ne s'entrecroise comme vous le décrivez, vous devez appliquer manuellement l'exclusion mutuelle, par exemple:
public void safePrintln(String s) {
synchronized (System.out) {
System.out.println(s);
}
}
Bien entendu, cet exemple n'est qu'une illustration et ne doit pas être considéré comme une "solution"; il y a de nombreux autres facteurs à considérer. Par exemple, la méthode safePrintln(...)
ci-dessus n'est sûre que si tout le code utilise cette méthode et que rien n'appelle System.out.println(...)
directement.
Le code source d'OpenJDK répond à votre question:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
Tant que vous ne modifiez pas le OutputStream
via System.setOut
il est thread-safe.
Bien qu'il soit sûr pour les threads, de nombreux threads peuvent écrire dans System.out
tel 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");
peut lire
1
2
A
3
B
C
entre autres combinaisons.
Donc, pour répondre à votre question:
Lorsque vous écrivez à System.out
- il acquiert un verrou sur l'instance OutputStream
- il écrira alors dans le tampon et videra immédiatement.
Une fois le verrou libéré, le OutputStream
est vidé et écrit dans. Il n'y aurait pas d'instance où vous auriez des chaînes différentes jointes comme 1A 2B
.
Modifier pour répondre à votre modification:
Cela n'arriverait pas avec System.out.println
. Étant donné que PrintStream
synchronise l'intégralité de la fonction, il remplira le tampon, puis le purgera atomiquement. Tout nouveau thread entrant aura désormais un nouveau tampon avec lequel travailler.
Juste pour clarifier, disons que vous avez deux fils, celui qui imprime "ABC"
et un autre qui imprime "DEF"
. Vous n'obtiendrez jamais de sortie comme celle-ci: ADBECF
, mais vous pouvez obtenir soit
ABC
DEF
ou
DEF
ABC