Java: Système.out.println et du Système.err.println hors de l'ordre
Mon System.out.println()
et System.err.println()
appels ne sont pas en cours d'impression de la console dans l'ordre je les fais.
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
System.out.println("out");
System.err.println("err");
}
}
Ce produit:
out
out
out
out
out
err
err
err
err
err
Au lieu d'une alternance de out
et err
. Pourquoi est-ce?
Vous devez vous connecter pour publier un commentaire.
Ils sont différents courants et sont purgées à des moments différents.
Si vous mettez
à l'intérieur de la boucle, il fonctionnera comme prévu.
Pour clarifier, les flux de sortie sont mis en cache de sorte que tous les va écrire dans cette mémoire tampon. Après une période de calme, ils sont en fait écrits.
Vous écrire à deux tampons, puis après une période d'inactivité, ils sont vidés (l'un après l'autre).
System.out
etSystem.err
devrait être auto-vidé à chaque retour à la ligne, qui est clairement présente comme l'utilisation d'appels deprintln()
. Donc cela ne devrait pas faire une différence.Ceci est provoqué par une fonction de la JVM et à moins de faire un hack comme celui fourni par Marcus A. ce n'est pas vraiment facile à contourner. Le
.flush()
fonctionne dans ce cas, mais la raison pour cela est beaucoup plus compliqué à contourner.Ce qui se passe ici?
Lorsque vous programmez en Java vous n'êtes pas raconter l'ordinateur directement quoi faire, vous dites à la JVM (Java Virtual Machine) ce que vous voulez qu'il fasse. Et il va le faire, mais d'une façon plus efficace. Votre code n'est pas exacte des instructions détaillées, dans ce cas vous avais seulement besoin d'un compilateur comme en C et C++, la JVM prend votre code comme une liste de spécification pour ce qu'il est censé optimiser et puis le faire. C'est ce qui se passe ici. Java voit que vous êtes en repoussant les chaînes en deux tampon différents flux. Le moyen le plus efficace de le faire est par la mise en mémoire tampon toutes les chaînes que vous souhaitez que les flux de sortie et de sortie. Cela produira un flux à l'époque, essentiellement la transformation de votre code faire quelque chose comme ceci (attention: le pseudo-code):
Parce que c'est plus efficace, c'est ce que la JVM va faire à la place. L'ajout de la
.flush()
dans la boucle de signal à la JVM que la couleur doit être fait dans chaque boucle, qui ne peut pas être améliorée avec la méthode ci-dessus. Mais si vous le souci d'expliquer comment cela fonctionne, aurait laissé en dehors de la boucle, la JVM va réorganiser votre code pour avoir l'impression de la dernière, parce que c'est plus efficace.Ce code sera toujours ré-organisé à quelque chose comme ceci:
Parce que la mise en mémoire tampon de nombreux tampons seulement à rincer à droite après prend beaucoup plus de temps que pour le tampon de tout le code pour être mis en mémoire tampon, puis rincer en même temps.
Comment le résoudre
C'est là où le code-le design et l'architecture peuvent entrer en jeu; vous un peu de ne pas résoudre ce problème. Pour contourner ce problème, vous devez le rendre plus efficace d'impression en mémoire tampon/couleur, impression en mémoire tampon de rinçage/de tampon toutes les rincer. Ce sera probablement vous attirer dans un mauvais design. Si il est important pour vous, comment la sortie en ordonnée, je vous suggère d'essayer une approche différente. Pour la boucle avec
.flush()
est une façon de le pirater, mais vous avez encore le piratage de la JVM de la fonction de ré-organiser et optimiser votre code pour vous.*
Je ne peux pas vérifier que le tampon que vous avez ajouté à la première aura toujours l'impression première, mais le plus probable.Si vous utilisez l'Éclipse de la console, il semble y avoir deux différents phénomènes à l'œuvre:
Un, comme décrit par @Gemtastic, est la Jvm de la manipulation des cours d'eau et l'autre est la voie de l'Éclipse lit ces cours d'eau, tel que mentionné par @DraganBozanovic. Depuis que je suis à l'aide d'Eclipse, l'élégant
flush()
-solution posté par @BillK, qui traite uniquement de la JVM question, ce n'est pas suffisant.J'ai fini par écrire moi-même un helper-classe appelée
EclipseTools
avec le contenu suivant (et le paquet nécessaire de déclaration et les importations). C'est un peu un hack mais résout ces deux problèmes:À utiliser, il suffit d'appeler
EclipseTools.fixConsole()
une seule fois au début de votre code.Fondamentalement, ce qui remplace les deux flux
System.err
etSystem.out
avec un ensemble personnalisé de cours d'eau que se contenter de transmettre leurs données à l'origine des flux, mais garder une trace des flux a été écrit à la dernière. Si le flux est écrit à des changements, par exemple unSystem.err.something(...)
suivie par unSystem.out.something(...)
, il vide la sortie du dernier flux et attend 200ms pour donner l'Éclipse de la console de temps pour terminer l'impression qu'il.Remarque: Les 200ms sont juste un accidenté de la valeur initiale. Si ce code réduit, mais n'élimine pas le problème pour vous, augmentez le délai dans
Thread.sleep
de 200 à quelque chose de plus élevé jusqu'à ce qu'il fonctionne. Alternativement, si ce retard de travaux, mais les impacts les performances de votre code (si vous alternez les ruisseaux souvent), vous pouvez essayer de réduire progressivement jusqu'à ce que vous commencez à recevoir des erreurs.Les deux
println
déclarations sont traitées par deux threads différents. La sortie dépend dans quel environnement vous exécutez le code dans.Pour exemple, j'ai exécuté le code suivant à l'Ide et de la ligne de commande 5 fois chacun.
Ce résultat dans la sortie suivante:
Ligne de commande
IntelliJ:
Je suppose que les différents environnements gère les tampons différemment.
Une façon de voir que ces cours d'eau sont en effet gérées par différents threads est d'ajouter un
sleep
instruction dans la boucle. Vous pouvez essayer de varier la valeur que vous définissez pour le sommeil et de voir que ceux-ci sont en effet gérées par différents threads.La sortie, dans ce cas, s'est avéré être
Un moyen de le forcer à imprimer dans le même ordre serait d'utiliser le
.flush()
, qui a travaillé pour moi. Mais itseems que pas tout le monde a le droit de résultats avec elle.Les deux flux traités par 2 deux threads différents est probablement la raison pour laquelle nous voyons parfois des
ERROR
message imprimé par certaines bibliothèques que nous utilisons, l'obtention d'imprimés avant que certains d'impression des déclarations que nous étions censés voir en fonction de l'ordre d'exécution.C'est un bug dans Eclipse. Il semble que Eclipse utilise des threads séparés de lire le contenu de
out
eterr
flux sans aucune synchronisation.Si vous compilez la classe et de l'exécuter dans la console (avec le classique
java <main class name>
), l'ordre est comme prévu.J'ai utilisé du fil d'imprimer la sortie du Système.et du Système.err séquentiellement comme: