J'ai besoin d'une solution pour arrêter correctement le thread en Java.
J'ai une IndexProcessor
classe qui implémente l'interface Runnable:
public class IndexProcessor implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
@Override
public void run() {
boolean run = true;
while (run) {
try {
LOGGER.debug("Sleeping...");
Thread.sleep((long) 15000);
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
run = false;
}
}
}
}
Et j'ai une ServletContextListener
classe qui démarre et arrête le fil:
public class SearchEngineContextListener implements ServletContextListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);
private Thread thread = null;
@Override
public void contextInitialized(ServletContextEvent event) {
thread = new Thread(new IndexProcessor());
LOGGER.debug("Starting thread: " + thread);
thread.start();
LOGGER.debug("Background process successfully started.");
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOGGER.debug("Stopping thread: " + thread);
if (thread != null) {
thread.interrupt();
LOGGER.debug("Thread successfully stopped.");
}
}
}
Mais lorsque j'arrête Tomcat, j'obtiens l'exception dans ma classe IndexProcessor:
2012-06-09 17:04:50,671 [Thread-3] ERROR IndexProcessor Exception
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at lt.ccl.searchengine.processor.IndexProcessor.run(IndexProcessor.java:22)
at java.lang.Thread.run(Unknown Source)
J'utilise JDK 1.6. La question est donc:
Comment puis-je arrêter le fil et ne lever aucune exception?
PS Je ne veux pas utiliser la .stop();
méthode car elle est obsolète.
java
multithreading
listener
Paulius Matulionis
la source
la source
InterruptedException
. C'est ce que je pense, mais je me demande aussi comment est la voie standard.InterruptedException
peut être trouvée à ibm.com/developerworks/library/j-jtp05236 .Réponses:
Dans la
IndexProcessor
classe, vous avez besoin d'un moyen de définir un indicateur qui informe le thread qu'il devra se terminer, similaire à la variablerun
que vous avez utilisée uniquement dans la portée de la classe.Lorsque vous souhaitez arrêter le thread, vous définissez ce drapeau et appelez
join()
le thread et attendez qu'il se termine.Assurez-vous que l'indicateur est thread-safe en utilisant une variable volatile ou en utilisant des méthodes getter et setter qui sont synchronisées avec la variable utilisée comme indicateur.
Puis dans
SearchEngineContextListener
:la source
L'utilisation
Thread.interrupt()
est une façon parfaitement acceptable de le faire. En fait, c'est probablement préférable à un drapeau comme suggéré ci-dessus. La raison en est que si vous êtes dans un appel de blocage interruptible (commeThread.sleep
ou en utilisant des opérations de canal java.nio), vous pourrez en fait sortir immédiatement.Si vous utilisez un indicateur, vous devez attendre la fin de l'opération de blocage, puis vous pouvez vérifier votre indicateur. Dans certains cas, vous devez quand même le faire, par exemple en utilisant standard
InputStream
/OutputStream
qui ne sont pas interruptibles.Dans ce cas, lorsqu'un thread est interrompu, il n'interrompra pas l'IO, cependant, vous pouvez facilement le faire régulièrement dans votre code (et vous devez le faire à des points stratégiques où vous pouvez arrêter et nettoyer en toute sécurité)
Comme je l'ai dit, le principal avantage
Thread.interrupt()
est que vous pouvez immédiatement interrompre les appels interruptibles, ce que vous ne pouvez pas faire avec l'approche du drapeau.la source
interrupt()
peut être correct, mais dans de nombreux autres cas, il ne l'est pas (par exemple, si une ressource doit être fermée). Si quelqu'un change le fonctionnement interne de la boucle, vous devez vous rappeler de passerinterrupt()
à la méthode booléenne. J'irais pour le chemin sûr depuis le début et j'utiliserais le drapeau.Réponse simple: vous pouvez arrêter un thread INTERNE de l'une des deux manières suivantes:
Vous pouvez également arrêter les discussions EXTERNE:
system.exit
(cela tue tout votre processus)interrupt()
méthode de l'objet thread *kill()
oustop()
)*: L'attente est que cela est censé arrêter un thread. Cependant, ce que le thread fait réellement lorsque cela se produit dépend entièrement de ce que le développeur a écrit lorsqu'il a créé l'implémentation du thread.
Un modèle courant que vous voyez avec les implémentations de méthode d'exécution est un
while(boolean){}
, où le booléen est généralement quelque chose nomméisRunning
, c'est une variable membre de sa classe de threads, il est volatile, et généralement accessible par d'autres threads par une méthode de définition de sortes, par exemplekill() { isRunnable=false; }
. Ces sous-programmes sont agréables car ils permettent au thread de libérer toutes les ressources qu'il détient avant de se terminer.la source
Vous devez toujours terminer les threads en vérifiant un indicateur dans la
run()
boucle (le cas échéant).Votre fil devrait ressembler à ceci:
Ensuite, vous pouvez terminer le fil en appelant
thread.stopExecuting()
. De cette façon, le fil est terminé propre, mais cela prend jusqu'à 15 secondes (en raison de votre sommeil). Vous pouvez toujours appeler thread.interrupt () si c'est vraiment urgent - mais la manière préférée devrait toujours être de vérifier l'indicateur.Pour éviter d'attendre 15 secondes, vous pouvez répartir le sommeil comme ceci:
la source
Thread
- il implémenteRunnable
- vous ne pouvez pas appeler deThread
méthodes dessus sauf si vous le déclarez comme unThread
cas auquel vous ne pouvez pas appelerstopExecuting()
En règle générale, un thread se termine lorsqu'il est interrompu. Alors, pourquoi ne pas utiliser le booléen natif? Essayez isInterrupted ():
ref- Comment puis-je tuer un fil? sans utiliser stop ();
la source
Pour synchroniser les threads, je préfère utiliser
CountDownLatch
ce qui aide les threads à attendre la fin du processus. Dans ce cas, la classe de travail est configurée avec uneCountDownLatch
instance avec un nombre donné. Un appel à laawait
méthode se bloquera jusqu'à ce que le nombre actuel atteigne zéro en raison des appels de lacountDown
méthode ou que le délai d'expiration soit atteint. Cette approche permet d'interrompre un thread instantanément sans avoir à attendre le temps d'attente spécifié:Lorsque vous souhaitez terminer l'exécution de l'autre thread, exécutez countDown sur le
CountDownLatch
etjoin
le thread sur le thread principal:la source
Quelques informations supplémentaires. Le drapeau et l'interruption sont suggérés dans le document Java.
https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
Pour un thread qui attend pendant de longues périodes (par exemple, pour la saisie), utilisez
Thread.interrupt
la source
Je n'ai pas réussi à faire fonctionner l'interruption sous Android, j'ai donc utilisé cette méthode, elle fonctionne parfaitement:
la source
volatile
. Voir docs.oracle.com/javase/specs/jls/se9/html/jls-17.html#jls-17.3 .Parfois j'essaierai 1000 fois dans mon onDestroy () / contextDestroyed ()
la source