2010-03-21 6 views
-1

J'ai une version courte de la question:Est-ce un bon moyen de fermer un thread?

  1. Je commence un fil comme ça: counter.start();, où counter est un fil.
  2. Au moment où je veux arrêter le fil je fais ça: counter.interrupt()
  3. Dans mon fils je fais régulièrement cette vérification: Thread.interrupted(). S'il donne true I return du thread et, par conséquent, il s'arrête.

Et voici quelques détails, si nécessaire:

Si vous avez besoin de plus de détails, ils sont ici. A partir du fil d'expédition inventer je commence un fil de compteur de cette façon:

public static void start() { 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      showGUI(); 
      counter.start(); 
     } 
    }); 
} 

où le fil est défini comme:

public static Thread counter = new Thread() { 
    public void run() { 
     for (int i=4; i>0; i=i-1) { 
      updateGUI(i,label); 
      try {Thread.sleep(1000);} catch(InterruptedException e) {}; 
     } 
      // The time for the partner selection is over. 
     SwingUtilities.invokeLater(new Runnable() { 
       public void run() {  
       frame.remove(partnerSelectionPanel); 
       frame.add(selectionFinishedPanel); 
       frame.invalidate(); 
       frame.validate(); 
      } 
     }); 
    } 
}; 

Le fil effectue le compte à rebours dans la fenêtre « première » (il montre la maison beaucoup de temps à gauche). Si la limite de temps est terminée, le thread ferme la "première" fenêtre et en génère une nouvelle. Je veux modifier mon fil de la manière suivante:

public static Thread counter = new Thread() { 
    public void run() { 
     for (int i=4; i>0; i=i-1) { 
      if (!Thread.interrupted()) { 
       updateGUI(i,label); 
      } else { 
       return; 
      } 
      try {Thread.sleep(1000);} catch(InterruptedException e) {}; 
     } 
     // The time for the partner selection is over. 
     if (!Thread.interrupted()) { 
      SwingUtilities.invokeLater(new Runnable() { 
       public void run() {  
       frame.remove(partnerSelectionPanel); 
       frame.add(selectionFinishedPanel); 
       frame.invalidate(); 
       frame.validate(); 
      } 
     }); 
     } else { 
      return; 
     } 
    } 
}; 

AJOUTÉE:

En raison de certaines raisons pour lesquelles il ne fonctionne pas. J'ai une méthode qui interrompt le fil:

public static void partnerSelected() { 
    System.out.println("The button is pressed!!!!"); 
    counter.interrupt(); 
} 

Cette méthode est activée lorsqu'un bouton est enfoncé. Quand j'appuie sur le bouton, je vois la sortie correspondante dans le terminal (donc cette méthode est activée et elle fait quelque chose). Mais à cause de certaines raisons, il n'interrompt pas le fil. Voici le code du fil:

public static Thread counter = new Thread() { 
    public void run() { 
     for (int i=40; i>0; i=i-1) { 
       if (Thread.interrupted()) { 
        System.out.println("Helloo!!!!!!!!!!!!!!!"); 
        return; 
       } 
      updateGUI(i,label); 
      try {Thread.sleep(1000);} catch(InterruptedException e) {}; 
     } 
      // The time for the partner selection is over. 
      if (Thread.interrupted()) { 
       System.out.println("Helloo!!!!!!!!!!!!!!!"); 
       return; 
      } 
     SwingUtilities.invokeLater(new Runnable() { 
       public void run() {  
       frame.remove(partnerSelectionPanel); 
       frame.add(selectionFinishedPanel); 
       frame.invalidate(); 
       frame.validate(); 
      } 
     }); 
    } 
}; 

P.S. Je ne vois pas "Bonjour !!!!!!!!!!!!!" dans le terminal ...

+0

wiki communautaire? –

+2

@Jamie: Pas question Jose. C'est une question "standard" légitime. –

+0

@OP: Re votre édition: Vous devez réaffirmer l'état interrompu (voir mon article) dans le bloc 'catch' (pour votre' Timer.sleep'). –

Répondre

5

Assez proche de la bonne idée. Cependant, dans votre catch (InterruptedException) vous devriez avoir:

Thread.currentThread().interrupt(); 

pour que l'état interrompu va à nouveau et ne fait pas les choses dans le deuxième bloc.


Modifier pour rendre mon point plus clair (parce que la modification de l'OP semble avoir manqué mon point de départ :-P): vous devez écrire votre code comme ceci:

try { 
    for (int = 40; i > 0; --i) { 
     updateGUI(i, label); 
     Thread.sleep(1000); 
    } 
} catch (InterruptedException e) { 
    Thread.currentThread().interrupt(); // <-- THIS LINE IS IMPORTANT 
} 

Deuxième édition pour expliquer ce que l'interruption fait. :-)

Lorsque vous appelez thread.interrupt(), l'indicateur interrompu de ce thread est défini. Ce drapeau ne fait rien par lui-même; c'est juste une variable. La raison en est que l'interruption supporte quelque chose appelé "gestion de threads coopérative", où le code courant du thread décide quoi faire quand il est interrompu (plutôt que d'être forcé de quitter sur place).

Certaines fonctions intégrées dans le JDK, comme Thread.sleep, ou Object.wait, ou Lock.lockInterruptibly, seront chèque le drapeau, et si elle est définie, ça va jeter un InterruptedException après avoir terminé le drapeau. Par conséquent, si vous appelez l'une de ces fonctions, vous n'avez pas besoin de vérifier manuellement l'indicateur interrompu. Mais si vous ne le faites pas, par exemple, si vous effectuez un traitement intensif au lieu d'attendre quelque chose, vous devez vérifier périodiquement le drapeau.

Il y a deux façons de vérifier le drapeau:

  1. interrupted()
  2. isInterrupted()

Le premier efface l'indicateur interrompu; le second ne le fait pas. Vous devez décider quelle version est la plus correcte pour votre logique d'application.

+0

Chris Jester-Young, je ne comprends pas quand l'exception InterruptedException sera lancée? Chaque fois que j'interromps le fil? Donc, je n'ai pas besoin de nous 'if (Thread.interrupted())' du tout? – Roman

+1

@Roman: 'InterruptedException' est levé si l'indicateur interrompu est défini au moment où' Thread.sleep' est appelé, ou si le thread est interrompu pendant le sommeil. Si vous n'appelez pas l'une des fonctions "en attente", aucune exception InterruptedException n'est levée, vous devez donc vérifier vous-même. –

+1

@Roman: Lorsqu'une exception InterruptedException est levée, l'indicateur interrompu est effacé. Donc, vous devez le redéfinir si vous avez du code postérieur qui le vérifie. C'est ce que fait le 'Thread.currentThread(). Interrupt()'. –

0

Oui, il est le chemin à parcourir

+0

@Ricket: Non ce n'est pas! C'est toujours la façon standard d'interrompre un thread, car cela fonctionne sur une base coopérative. Lisez Java Concurrency in Practice pour plus de détails. –

+0

@Chris Je l'ai réalisé et supprimé mon commentaire juste après l'avoir posté; Je pensais à 'stop()'. – Ricket

0

Je voudrais éditer et notez que je l'ai appris une leçon aujourd'hui. Il n'y a aucune raison d'implémenter un booléen comme je l'explique dans les deux paragraphes suivants; le mécanisme d'interruption fait cela pour moi. Pour une raison quelconque, j'avais supposé que "interruption" arrête le fil mort dans ses traces (je ne sais pas ce que je pensais qu'Interrupted() faisait alors!).

Donc, voici un exemple de ce qu'il ne faut pas faire. Continuez à utiliser votre technique d'interruption!

(s'il vous plaît ne me downvote pas ...)


Je tends à éviter d'interruption, mais surtout pour arrêter un fil. Dans votre cas, vous essayez d'utiliser interruption() comme alternative à stop(), qui a été déprécié pour une bonne raison.Tout ce que vous devez faire est de déclarer un booléen qui représente si le thread doit arrêter de compter, et que le thread vérifie en permanence cette valeur booléenne. Ensuite, lorsque le thread parent est prêt pour l'arrêt du compteur, il doit définir le booléen sur true (stop), ce qui provoque l'arrêt du thread de compteur dès qu'il vérifie à nouveau la valeur.

Dans la définition de classe anonyme de votre thread de compteur, ajoutez public volatile boolean shouldStop;. Au début de run(), définissez shouldStop = false;. Remplacez ensuite tous Thread.interrupted() par shouldStop (dans vos instructions if). Enfin, au lieu d'appeler counter.interrupt(), dites simplement counter.shouldStop = true;. Vous pouvez en outre appeler counter.join() juste après avoir réglé shouldStop=true si vous voulez vous assurer que le compteur s'est arrêté avant de continuer.

+1

Non, mauvaise idée. Java a un mécanisme intégré pour signaler si un thread doit s'arrêter (interruption); Ne le subvertis pas. –

+0

+1. OMI il est préférable d'avoir votre propre drapeau indiquant si le fil devrait être en cours d'exécution. Je ne me souviens pas d'où vient cette connaissance, mais je me souviens juste que c'est la meilleure façon de le faire :). – pajton

+0

@pajton: Le drapeau interrompu _is_ est un tel drapeau, sauf qu'il est également respecté par les bibliothèques JDK (telles que Thread.sleep ou Object.wait), alors qu'un drapeau roulé à la main ne sera observé par aucun des bibliothèques standard. –

0
  1. Il est considéré comme une meilleure façon (link) à utiliser la variable volatile séparée (isStopped booléenne) à cet effet.

  2. On suppose que interrupted() méthode de la valeur passe de true à false si votre fils a été interrompu, i.e. .:

System.out.println (Thread.interrupted()); //true

System.out.println (Thread.interrupted()); //false

L'alternative est la méthode isInterrupted().

+0

Le lien ne dit pas "c'est considéré comme un meilleur moyen" du tout. C'est un exemple d'utilisation d'un booléen séparé mais il ne traite même pas de Thread.isInterrupted(), et encore moins de ce qui est le mieux. Si c'est mieux, j'aimerais savoir pourquoi. – EJP

1

Consultez cet article de la newsletter JavaSpecialists, qui couvre la procédure interrupt() et gère correctement cette opération.

+0

+1 pour le lien très intéressant :) –

Questions connexes