web-dev-qa-db-fra.com

Java: La boucle `while (true) {...}` dans un thread est-elle mauvaise? Quelle est l'alternative?

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.

22
Mr. Burgundy

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 ().

16
JRL
while (!stop_running) { ... }

... peut-être? Une sorte d'indicateur de sortie est souvent utilisé pour contrôler le processus en cours d'exécution.

7
souser12345

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.

7
Eric Petroelje

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
3

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

1
Gilles

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.

0
Stefan Kendall

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

0
Fritz Duchardt

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. 

0

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.

0
JustJeff

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?

0
Buhake Sindi