web-dev-qa-db-fra.com

La sortie multi-thread de System.out.println est-elle entrelacée

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
65
Ellen Spertus

É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.

56
maerics

Le code source d'OpenJDK répond à votre question:

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

Référence: http://hg.openjdk.Java.net/jdk6/jdk6/jdk/file/39e8fe7a0af1/src/share/classes/Java/io/PrintStream.Java

19
twimo

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.

9
John Vint

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
2
parkovski