web-dev-qa-db-fra.com

Comment tuez-vous un fil en Java?

Comment tuez-vous un Java.lang.Thread en Java?

358
flybywire

Voir ceci Discussion de Sun sur la raison pour laquelle ils ont déconseillé Thread.stop() . Il explique en détail pourquoi il s’agissait d’une mauvaise méthode et ce qui devrait être fait pour arrêter en toute sécurité les threads en général.

Ils recommandent d’utiliser une variable partagée comme indicateur qui demande au thread d’arrière-plan de s’arrêter. Cette variable peut ensuite être définie par un autre objet demandant la fin du thread.

183
JaredPar

Généralement tu ne ..

Vous lui demandez d'interrompre ce qu'il fait en utilisant Thread.interrupt () (lien javadoc)

Une bonne explication de la raison est dans le javadoc ici (lien de la note technique Java)

126
Fredrik

Dans Java, les threads ne sont pas supprimés, mais l'arrêt d'un thread s'effectue de manière coopérative . Le thread est invité à se terminer et le thread peut alors se fermer normalement.

Souvent, un champ volatile boolean est utilisé que le thread vérifie périodiquement et se termine lorsqu'il est défini sur la valeur correspondante.

Je ne voudrais pas utiliser un boolean pour vérifier si le fil doit se terminer . Si vous utilisez volatile comme modificateur de champ, cela fonctionnera de manière fiable, mais si votre code devient plus complexe, car il utilise d'autres méthodes de blocage dans la boucle while, il se peut que votre code ne pas terminer du tout ou au moins prend plus de temps comme vous le souhaitez.

Certaines méthodes de bibliothèque bloquantes prennent en charge les interruptions.

Chaque thread a déjà un drapeau booléen statut interrompu et vous devriez vous en servir. Il peut être implémenté comme ceci:

public void run() {
   try {
      while (!interrupted()) {
         // ...
      }
   } catch (InterruptedException consumed)
      /* Allow thread to exit */
   }
}

public void cancel() { interrupt(); }

Code source adapté de Java Concurrency in Practice . Puisque la méthode cancel() est publique, vous pouvez laisser un autre thread l'appeler comme vous le souhaitez.

63
Konrad Reiche

Une solution consiste à définir une variable de classe et à l'utiliser comme sentinelle.

Class Outer {
    public static volatile flag = true;

    Outer() {
        new Test().start();
    }
    class Test extends Thread {

        public void run() {
            while (Outer.flag) {
                //do stuff here
            }
        }
    }

}

Définissez une variable de classe externe, c'est-à-dire flag = true dans l'exemple ci-dessus. Réglez-le sur false pour "tuer" le fil.

19
karim79

Il y a un moyen de le faire. Mais si vous deviez l'utiliser, vous êtes soit un mauvais programmeur, soit vous utilisez un code écrit par de mauvais programmeurs. Donc, vous devriez penser à cesser d’être un mauvais programmeur ou à cesser d’utiliser ce mauvais code. Cette solution est uniquement destinée aux situations où: IL IS AUCUN AUTRE.

Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );
12
VadimPlatonov

Je veux ajouter plusieurs observations, basées sur les commentaires accumulés.

  1. Thread.stop () arrêtera un thread si le gestionnaire de sécurité le permet.
  2. Thread.stop () est dangereux. Cela dit, si vous travaillez dans un environnement JEE et que vous n'avez aucun contrôle sur le code appelé, cela peut s'avérer nécessaire.
  3. Vous ne devriez jamais arrêter de stopper un thread de traitement de conteneur. Si vous souhaitez exécuter du code qui a tendance à se bloquer, démarrez (avec précaution) un nouveau thread de démon et surveillez-le, en supprimant si nécessaire.
  4. stop () crée une nouvelle erreur ThreadDeath sur le thread appelant et provoque ensuite l'application de cette erreur à la cible fil. Par conséquent, la trace de la pile est généralement sans valeur.
  5. Dans JRE 6, stop () vérifie auprès du gestionnaire de sécurité, puis appelle stop1 () qui appelle stop0 (). stop0 () est un code natif.
8
Steve11235

Je voterais pour Thread.stop().

Par exemple, vous avez une opération de longue durée (comme une requête réseau). Soi-disant, vous attendez une réponse, mais cela peut prendre du temps et l'utilisateur doit accéder à une autre interface utilisateur. Ce fil en attente est maintenant a) inutile b) un problème potentiel car lorsqu'il obtiendra un résultat, il sera totalement inutile et il déclenchera des rappels pouvant entraîner un certain nombre d'erreurs.

Tout cela et il peut faire un traitement de réponse qui pourrait être intense en CPU. Et vous, en tant que développeur, ne pouvez même pas l'arrêter, car vous ne pouvez pas insérer de lignes if (Thread.currentThread().isInterrupted()) dans tout le code.

Donc, l'impossibilité d'arrêter de force un fil c'est bizarre.

7
Anfet

La question est plutôt vague. Si vous vouliez dire "comment puis-je écrire un programme pour qu'un thread cesse de fonctionner quand je le souhaite", alors diverses autres réponses devraient être utiles. Mais si vous vouliez dire "j'ai un problème urgent avec un serveur que je ne peux pas redémarrer maintenant et que j'ai juste besoin d'un thread particulier pour mourir", alors vous avez besoin d'un outil d'intervention correspondant aux outils de contrôle tels que jstack.

À cette fin, j'ai créé jkillthread . Voir ses instructions d'utilisation.

5
Jesse Glick

Il existe bien sûr le cas où vous exécutez une sorte de code qui n’est pas totalement fiable. (Personnellement, je le fais en permettant aux scripts téléchargés de s'exécuter dans mon environnement Java. Oui, une cloche d'alarme de sécurité sonne partout, mais cela fait partie de l'application.) Dans cet exemple malheureux, vous êtes simplement avoir de l'espoir en demandant aux scénaristes de respecter une sorte de signal booléen d'exécution/de non-exécution. Votre seul échec décent consiste à appeler la méthode stop sur le thread si, par exemple, il s’exécute plus longtemps que prévu.

Mais, ceci est juste "décent", et non absolu, car le code pourrait capter l'erreur ThreadDeath (ou toute exception que vous avez explicitement générée), et ne pas la rediffuser comme un fil de discussion gentilhomme est censé le faire. AFAIA ne constitue donc pas une solution de sécurité absolue.

4
mlohbihler

Il n'y a aucun moyen de tuer gracieusement un fil.

Vous pouvez essayer d'interrompre le fil, une stratégie commune consiste à utiliser un comprimé empoisonné pour envoyer un message au fil afin de l'arrêter

public class CancelSupport {
    public static class CommandExecutor implements Runnable {
            private BlockingQueue<String> queue;
            public static final String POISON_PILL  = “stopnow”;
            public CommandExecutor(BlockingQueue<String> queue) {
                    this.queue=queue;
            }
            @Override
            public void run() {
                    boolean stop=false;
                    while(!stop) {
                            try {
                                    String command=queue.take();
                                    if(POISON_PILL.equals(command)) {
                                            stop=true;
                                    } else {
                                            // do command
                                            System.out.println(command);
                                    }
                            } catch (InterruptedException e) {
                                    stop=true;
                            }
                    }
                    System.out.println(“Stopping execution”);
            }

    }

}

BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);

http://anandsekar.github.io/cancel-support-for-threads/

3
Anand Rajasekar

Généralement, vous ne tuez pas, n'arrêtez pas et n'interrompez pas un thread (ni ne vérifiez s'il est interrompu ()), mais le laissez se terminer naturellement.

C'est simple. Vous pouvez utiliser n’importe quelle boucle avec la variable booléenne (volatile) dans la méthode run () pour contrôler l’activité du thread. Vous pouvez également revenir du thread actif au thread principal pour l'arrêter.

De cette façon, vous tuez gracieusement un fil :).

2
1
splashout

Les tentatives de terminaison de fil abrupte sont une mauvaise pratique de programmation bien connue et la preuve d'une conception d'application médiocre. Tous les threads de l'application multithread partagent explicitement et implicitement le même état de processus et sont contraints de coopérer pour rester cohérents, sinon votre application sera sujette aux bogues qui seront très difficiles à diagnostiquer. Il incombe donc au développeur de fournir l’assurance de cette cohérence grâce à une conception d’application claire et précise.

Il existe deux solutions principales correctes pour les terminaisons de fils contrôlées:

  • Utilisation du drapeau volatile partagé
  • Utilisation de la paire de méthodes Thread.interrupt () et Thread.interrupted ().

Vous trouverez ici des explications complètes et détaillées sur les problèmes liés à la terminaison abrupte de threads, ainsi que des exemples de solutions fausses et correctes pour la terminaison de threads contrôlées:

https://www.securecoding.cert.org/confluence/display/Java/THI05-J.+Do+not+use+Thread.stop%28%29+to+terminate+threads

1
ZarathustrA

"Tuer un fil" n'est pas la bonne phrase à utiliser. Voici un moyen d’implémenter gracieusement l’achèvement/la sortie du fil sur volonté:

Runnable que j'ai utilisé:

class TaskThread implements Runnable {

    boolean shouldStop;

    public TaskThread(boolean shouldStop) {
        this.shouldStop = shouldStop;
    }

    @Override
    public void run() {

        System.out.println("Thread has started");

        while (!shouldStop) {
            // do something
        }

        System.out.println("Thread has ended");

    }

    public void stop() {
        shouldStop = true;
    }

}

La classe de déclenchement:

public class ThreadStop {

    public static void main(String[] args) {

        System.out.println("Start");

        // Start the thread
        TaskThread task = new TaskThread(false);
        Thread t = new Thread(task);
        t.start();

        // Stop the thread
        task.stop();

        System.out.println("End");

    }

}
1
Adesh

Je n'ai pas eu l'interruption de travailler dans Android, alors j'ai utilisé cette méthode, fonctionne parfaitement:

boolean shouldCheckUpdates = true;

private void startupCheckForUpdatesEveryFewSeconds() {
    Thread t = new Thread(new CheckUpdates());
    t.start();
}

private class CheckUpdates implements Runnable{
    public void run() {
        while (shouldCheckUpdates){
            //Thread sleep 3 seconds
            System.out.println("Do your thing here");
        }
    }
}

 public void stop(){
        shouldCheckUpdates = false;
 }
0
Mindborg