La boucle while (true) { ... }
dans les threads est-elle mauvaise? Quelle est l'alternative?
Mettre à jour; ce que j'essaie de ...
J'ai environ 10 000 threads, chacun consommant des messages de leurs files d'attente privées. J'ai un fil qui produit des messages un par un et les met dans la file d'attente du consommateur approprié. Chaque thread consommateur boucle en boucle indéfiniment, vérifiant qu'un message apparaît dans leur file d'attente et le traite.
Inside Consumer.Java:
@Override
public void run() {
while (true) {
Message msg = messageQueue.poll();
if (msg != null) {
... // do something with the message
}
}
}
Le producteur insère des messages dans les files de messages du consommateur à un rythme rapide (plusieurs millions de messages par seconde). Les consommateurs devraient traiter ces messages le plus rapidement possible!
Remarque: la while (true) { ... }
se termine par un message KILL envoyé par le producteur en tant que dernier message. Cependant, ma question concerne la bonne façon de faire passer ce message ...
S'il vous plaît voir la nouvelle question , concernant cette conception.
Au lieu de boucler à tout jamais et de casser ou de revenir, vous pouvez choisir de vérifier le statut interrompu.
while (!Thread.currentThread().isInterrupted()) {
try {
doWork();
wait(1000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
Si vos threads sont des tâches gérées par un ExecutorService, vous pouvez les faire se terminer normalement en appelant shutdownNow ().
while (!stop_running) { ... }
... peut-être? Une sorte d'indicateur de sortie est souvent utilisé pour contrôler le processus en cours d'exécution.
Pas intrinsèquement, non. Vous pouvez toujours payer en utilisant break
ou return
. Assurez-vous simplement de le faire (à un moment donné)
Le problème est que se passe-t-il lorsque votre fil n'a rien à faire? Si vous ne faites que passer en boucle pour vérifier une condition, votre thread va dévorer tout le processeur sans rien faire. Veillez donc à utiliser wait
pour que votre thread se bloque ou sleep
si vous n'avez rien à wait
.
Dépend de la définition de "mauvais". Cela signifie que la personne qui tente de lire le code doit chercher ailleurs la raison pour laquelle la boucle est terminée. Cela peut le rendre moins lisible.
Cette mentalité poussée à l'extrême résulte du mot clé COMEFROM. http://en.wikipedia.org/wiki/COMEFROM
10 COMEFROM 40
20 INPUT "WHAT IS YOUR NAME? "; A$
30 PRINT "HELLO, "; A$
40 REM
Il est préférable d’avoir la condition de terminaison sur la ligne while (...)
, mais parfois, la condition de terminaison est quelque chose que vous ne pouvez tester que quelque part au fond de la boucle. Alors c'est ce que break
est pour (ou des exceptions). En fait, votre thread doit peut-être fonctionner indéfiniment jusqu'à la fin de votre programme (avec System.exit
); alors while (true)
a définitivement raison.
Mais peut-être vous demandez ce qui devrait aller dans la boucle. Vous devez vous assurer d’inclure une opération de blocage, c’est-à-dire un appel de fonction dans lequel votre thread attendra que quelqu'un d’autre (un autre thread, un autre programme, le système d’exploitation) fasse quelque chose. Il s’agit généralement de Condition.wait
si vous programmez des verrous, lisez à partir d’une file de messages, lisez à partir d’un fichier ou d’une socket réseau, ou effectuez une autre opération d’E/S bloquante.
Notez que sleep
est généralement pas assez bon. Vous ne pouvez pas savoir quand les autres participants vont faire quelque chose, il n'y a donc aucun moyen d'éviter de vous réveiller trop souvent (perdant ainsi du temps processeur) ou trop rarement (ne réagissant donc pas aux événements à temps). Concevez toujours votre système de manière à ce que, lorsqu'un thread a terminé son travail, il en informe celui qui l'attend (souvent avec Condition.signal
ou en rejoignant).
Généralement, vous souhaiterez wait
sur une ressource quelconque pour effectuer un travail, ce qui vous masque les détails de threading. On dirait que vous voulez implémenter votre propre spinlock .
Voici un tutoriel sur le verrouillage, j'ai trouvé je google.
D'abord, la réponse directe à ce problème par Dough Lea:
Ce n’est presque jamais une bonne idée d’utiliser des spins nus dans l’attente des valeurs de variables. Utilisez Thread.onSpinWait, Thread.yield et/ou le blocage de la synchronisation pour mieux faire face au fait que "finalement" peut durer longtemps, en particulier lorsqu'il y a plus de threads que de cœurs sur un système.
http://gee.cs.oswego.edu/dl/html/j9mm.html
Thead.onSpinWait a été introduit avec Java 9. Cela pourrait ressembler à ceci.
while (true) {
while (messageQueue.peek() == null) {
Thread.onSpinWait();
}
// do something with the message
}
En appelant cette méthode dans chaque itération d'une construction de boucle spin-wait, le thread appelant indique au moteur d'exécution qu'il est en attente. Le moteur d'exécution peut prendre des mesures pour améliorer les performances de l'appel de constructions de boucle spin-wait.
https://docs.Oracle.com/javase/9/docs/api/Java/lang/Thread.html#onSpinWait--
Il semble que vous soyez occupé à attendre, en supposant une variable standard BlockingQueue
. Utilisez take
au lieu de poll
.
Sinon, for (;;)
est plus agréable que while (true)
, IMO.
Je vais habituellement avec un attribut de classe booléen appelé 'done', alors les méthodes d'exécution des threads ressemblent à
done = false;
while( !done ) {
// ... process stuff
}
Vous pouvez ensuite définir done = true pour tuer la boucle. Cela peut être fait depuis l'intérieur de la boucle, ou vous pouvez avoir une autre méthode pour la définir, afin que d'autres threads puissent tirer le bouchon.
while (true)
n'est pas mauvais s'il existe un moyen de sortir de la boucle, sinon l'appel sera exécuté indéfiniment.
Faire appel à while(true)
pour les 10 000 threads est une mauvaise pratique ... pourquoi n'avez-vous pas un sleep()
sur le thread pour permettre à d'autres threads de s'exécuter ou une stratégie de sortie si le thread se termine?