2010-07-07 6 views

Répondre

66

La bonne façon de le faire est d'avoir le run() du fil gardée par une variable boolean et le mettre à true de l'extérieur lorsque vous voulez arrêter, quelque chose comme:

class MyThread extends Thread 
{ 
    volatile boolean finished = false; 

    public void stopMe() 
    { 
    finished = true; 
    } 

    public void run() 
    { 
    while (!finished) 
    { 
     //do dirty work 
    } 
    } 
} 

Il était une fois une méthode stop() existait mais comme les états de la documentation

Cette méthode est intrinsèquement dangereuse. L'arrêt d'un thread avec Thread.stop l'amène à déverrouiller tous les moniteurs qu'il a verrouillés (comme conséquence naturelle de l'exception ThreadDeath non cochée propageant la pile). Si l'un des objets précédemment protégés par ces moniteurs était dans un état incohérent, les objets endommagés deviennent visibles aux autres threads, ce qui peut entraîner un comportement arbitraire.

C'est pourquoi vous devriez avoir un garde ..

+2

Voir le commentaire de Jon Skeet à la réponse de Bart - il s'applique également à la vôtre. –

+0

Si "fini" change pendant que vous faites votre "sale boulot" le fil ne se termine pas, alors vous devez faire une vérification périodique, par exemple avec un sommeil (x) dans la boucle, quelque chose qui n'est pas recommandé et vous donne une mauvaise performance, alors est-ce vraiment une bonne approche? –

+0

nous parlons de quitter un fil gracieusement. Forcer un thread à quitter au milieu de son sale boulot n'est pas une façon élégante de le faire. Vous devriez toujours attendre la prochaine itération sauf si vous avez une raison spécifique de l'interrompre. – Jack

4

Créez un booléen volatil stop quelque part. Ensuite, dans le code qui va dans le fil, faire régulièrement

if (stop) // end gracefully by breaking out of loop or whatever 

Pour arrêter le fil, mettre stop à true.

Je pense que vous devez le faire manuellement de cette façon. Après tout, seul le code qui s'exécute dans le thread a une idée de ce qui est et n'est pas gracieux.

+21

Notez que vous devez utiliser le verrouillage ou rendre le champ volatile pour vous assurer que le thread de lecture voit les modifications du thread d'écriture. –

+0

@Jon Skeet: Oui, ce serait mieux. Par curiosité cependant, combien de temps l'arrêt serait-il retardé si le champ n'est pas volatil? –

+5

@Bart: En pratique, probablement pas longtemps du tout. En théorie, pour toujours. –

10

Vous ne devriez pas tuer cette discussion d'autre. C'est considéré comme une mauvaise habitude. Cependant, il y a plusieurs façons. Vous pouvez utiliser l'instruction return à partir de la méthode run du thread. Ou vous pouvez vérifier si le fil a déjà été interrompu, puis il annulera son travail. F.e. :

while (!isInterrupted()) { 
    // doStuff 
} 
+0

La méthode run est vide, elle ne peut rien retourner. –

+3

vous pouvez utiliser l'instruction de retour vide avec le type de retour vide, la méthode se terminera – Xorty

+0

cela est similaire à la première réponse, sauf que vous utilisez return au lieu de simplement laisser la méthode run() quitter. Et oui, vous pouvez simplement utiliser return; et cela va sortir d'une méthode vide – Richard

3

Vous devez envoyer un message d'arrêt au thread et le thread lui-même doit prendre des mesures si le message a été reçu. Ceci est assez facile, si l'action de longue durée est à l'intérieur boucle:

public class StoppableThread extends Thread { 

    private volatile boolean stop = false; 

    public void stopGracefully() { 
    stop = true; 
    } 

    public void run() { 
    boolean finished = false; 
    while (!stop && !finished) { 
     // long running action - finished will be true once work is done 
    } 
    } 
} 
+1

Comme Jon Skeet a remarqué sur ma réponse, l'arrêt devrait être volatil –

+0

J'ai édité ma réponse mais irai et découvrirai, pourquoi il s'applique ici - dans votre réponse, j'ai pensé, il devait être volatil juste parce que vous n'avez pas mentionné un méthode et il semblait que le champ 'stop' devait être accessible directement. –

+1

Je me suis interrogé sur le mot-clé volatile avant et (sans essayer d'annoncer ma propre question :)), voici quelques réponses là-dessus: http://stackoverflow.com/questions/106591/do-you-ever- use-the-volatile-keyword-in-java – Richard

12

La mauvaise partie sur l'utilisation d'un drapeau pour arrêter votre fil est que si le fil est en attente ou dormir, alors vous devez attendre à finir d'attendre/dormir. Si vous appelez la méthode d'interruption sur le thread, cela provoquera l'arrêt de l'appel wait ou sleep avec une exception InterruptedException. L'appel à interruption() définit également une propriété interrompue que vous pouvez utiliser comme indicateur pour vérifier s'il faut quitter (dans le cas où le thread n'attend pas ou ne dort pas).

Vous pouvez écrire la méthode d'exécution du thread de sorte que l'exception InterruptedException soit interceptée en dehors de la logique de bouclage du thread ou vous pouvez intercepter l'exception dans la boucle et fermer l'appel en lançant l'exception. catch block pour l'exception InterruptedException afin que le thread ne perd pas de vue le fait qu'il a été interrompu. Le thread interrompu peut toujours garder le contrôle et terminer le traitement selon ses propres termes.Dites que je veux écrire un thread de travail qui fonctionne par incréments, où il y a un sommeil au milieu pour une raison quelconque, et je ne veux pas quitter le sommeil pour arrêter le traitement sans faire le travail restant pour cet incrément , je veux seulement à quitter si elle est en entre les incréments:

class MyThread extends Thread 
{ 
    public void run() 
    { 
     while (!Thread.currentThread().isInterrupted()) 
     { 
      doFirstPartOfIncrement(); 
      try { 
       Thread.sleep(10000L); 
      } catch (InterruptedException e) { 
       // restore interrupt flag 
       Thread.currentThread().interrupt(); 
      } 
      doSecondPartOfIncrement(); 
     } 
    } 
} 

Here is an answer to a similar question, including example code.

1

pour un fil pour s'arrêter, personne ne semble avoir mentionné (mis) en utilisant exception:

abstract class SelfStoppingThread extends Thread { 

    @Override 
    public final void run() { 
     try { 
      doRun(); 
     } catch (final Stop stop) { 
      //optional logging 
     } 
    } 

    abstract void doRun(); 

    protected final void stopSelf() { 
     throw new Stop(); 
    } 

    private static final class Stop extends RuntimeException {}; 

} 

Une sous-classe a juste besoin de surcharger doRun() normalement comme vous le feriez avec un Thread, et d'appeler stopSelf() chaque fois qu'elle a envie de s'arrêter. IMO est plus propre que d'utiliser un drapeau dans une boucle while.

Questions connexes