IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Comment Forcer le Kill d'un thread


Sujet :

Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Août 2003
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 36
    Par défaut Comment Forcer le Kill d'un thread
    Bonjour,

    Je ne trouve pas le moyen de détruire un thread sans utiliser de méthodes deprecated du style Beaucoup de sites conseillent d'utiliser un boolean qui determine l'etat du thread ... par exemple comme ci dessous décrit dans la FAQ Java de developpez.com :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    private boolean stopThread = false;
     
    public void run() {
            boolean fin = false;
     
            while( !fin ) {
                    try {
                            // traitement
     
                            synchronized(this) {
                                    Thead.yield();
     
                                    // lecture du boolean 
                                    fin = this.stopThread;
                            } 
                    } catch( InterruptedException e ) {
     
                    } 
            } 
    } 
     
    public synchronized void stop() {
            this.stopThread = true;
    }
    Mais ma problématique est que j'utilise une methode qui dure environ 2 minutes.
    J'aimerai pouvoir Forcer la destruction du thread pendant que cette méthode est entrain de s'executer.
    Voici le code de ma méthode en question ( C'est une insertion de données en base) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    ...
    stmt.execute("LOAD DATA INFILE 'datainsert.csv' INTO TABLE t_ma_table FIELDS TERMINATED BY ';';");
    ...
    Quelqu'un pourrait t'il me dire comment forcer le kill d'un thread en execution?

    Merci

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    802
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 802
    Par défaut
    Le seul moyen fiable de killer un Thread récalcitrant est de terminer le Thread principal de l'application. Il n'existe aucun autre moyen à ma connaissance de forcer l'arrêt d'un Thread.

    Et encore, même en terminant le Thread principal, il y a certaines conditions à remplir. On a en fait deux choix :
    1) Stopper la jvm avec System.exit(), ce qui a pour effet de killer tous les Thread.
    2) Définir le Thread à killer comme demon (Thread.setDaemon(true)). Le démon se terminera lorsqu'il ne restera que des démons. C'est-à-dire, si aucun autre Thread n'a été lancé, lorsque le Thread principal se terminera.

    En conséquence, pour killer à coup sûr un Thread, il faut stopper l'application.

    Une solution est de lancer le Thread à killer dans une instance spécifique de la jvm. Le problème est qu'une application java ne peut pas lancer directement une autre application java. Il faut passer par un bootstrap de type .bat ou .sh.

  3. #3
    Modérateur
    Avatar de wax78
    Homme Profil pro
    R&D - Palefrenier programmeur
    Inscrit en
    Août 2006
    Messages
    4 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : R&D - Palefrenier programmeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 4 096
    Par défaut
    Dans mes souvenir j'avais un truc similaire qui exécutait une requête SQL, qui si celle ci dépassait 500 ms devait se terminer et éventuellement recommencer.

    Le execute requête étant bloquant, je l'avais mis dans un thread que j'interrompais salement avec :

    et ca fonctionnait (par chance sans doute...),
    le stmt.execute était interrompus presque illico, maintenant ce n'est surement pas le mieux a faire mais je ne vois pas comment faire autrement...

    Sinon après une petite recherche je suis tombé la dessus, je ne sais ce que ca vaut : http://onjava.com/pub/a/onjava/2004/06/16/dbcancel.html
    ou alors ceci avec on dirait, un truc tout fait https://www.securecoding.cert.org/co...+be+terminated
    (Les "ça ne marche pas", même écrits sans faute(s), vous porteront discrédit ad vitam æternam et malheur pendant 7 ans)

    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par wax78 Voir le message
    le stmt.execute était interrompus presque illico, maintenant ce n'est surement pas le mieux a faire mais je ne vois pas comment faire autrement...
    L'appel à interrupt() est la meilleure solution ! Je ne vois pas en quoi ce ne serait pas propre !


    Le stop() est à éviter comme la peste car il arrête brutalement le thread, en laissant tout en l'état. Du coup on peut se retrouver avec des données en mémoire incohérente ou des ressources bloquées...

    Avec interrupt() on se contenter de demander au thread de bien vouloir s'arrêter. En gérant cela correctement on peut donc libérer tout ce qu'il faut et rendre la main dès que possible...


    Maintenant la seule contrainte c'est que les méthodes bloquantes doivent gérer cela, ce dans le cas présent cela doit dépendre du driver JDBC...

    Mais s'il ne gère pas cela, il n'y a pas vraiment de solution propre pour arrêter le thread (à moins d'arrêter carrément le programme).


    a++

    [edit] @wax78 : pour un timeout on peut utiliser directement la méthode setQueryTimeout()

  5. #5
    Modérateur
    Avatar de wax78
    Homme Profil pro
    R&D - Palefrenier programmeur
    Inscrit en
    Août 2006
    Messages
    4 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : R&D - Palefrenier programmeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 4 096
    Par défaut
    Bah oui j'ai dit sale pour être sure de ne pas me faire trop démontés si c'était pas bon

    Je pense qu'avec le connecteur Oracle (testé a l'époque) l'interrupt passait bien, pour avoir.

    Sinon bien vu pour le timeout ca peut toujours servir.
    (Les "ça ne marche pas", même écrits sans faute(s), vous porteront discrédit ad vitam æternam et malheur pendant 7 ans)

    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Août 2003
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 36
    Par défaut
    Je vous remercie pour vos réponses.

    J'utilise le stop actuellement car j'ai tenté le interrupt() mais cela ne fonctionne pas.

    J'ai fait par exemple un petit script pour tester ci dessous et le thread manifestement ne s'arrete pas, dans l'exemple l'execution devrait s'arreter des que (ou preske...) le compteur du Main atteint 4000 mais le thread continue son execution jusqu'a la fin (cpt = 50000 ds l'exemple)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public static void main(String[] args) {
     
    	Thread t = new Thread(new UpdateProcess("toto.zip"));
    	t.start();
    	int cpt = 0;
    	while (true) {
    		System.err.println("Main : " + cpt);
    		cpt++;
    		if (cpt == 4000)
    			t.interrupt();
    		if (cpt == 30000)
    			break;
    	}
    et mon thread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public class UpdateProcess implements Runnable {
    ...
    public void run() {
    	int cpt = 0;
    	while (true) {
    		cpt++;
    		System.out.println("Run :"+cpt);
    		if (cpt == 50000)
    		break;
    	}
    }
    ...
    Qqchose m'a échappé ?

    Merci

  7. #7
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Normal puisque tu ne vérifies jamais le status "interrupted" dans ton thread...

    Pour rappel le "interrupt" demande seulement au thread de s'arrêter, mais il ne l'arrêtera pas automatiquement.

    Tu pourrais par exemple faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	while ( ! Thread.interrupted() ) {
    a++

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Août 2003
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 36
    Par défaut
    Ah ok il faut verifier le statut.

    Il est donc impossible d'arreter le thread pdt l'execution de ma commande stmt.execute("LOAD DATA INFILE ..... ?

    Etant donnée que cette derniere n'est qu'une seule instruction et qu'elle a une durée d'environ 2 minutes.

    Je ne repasse jamais par le while durant l'execution de la requete ...

    Je ne suis donc foutu a part faire un thread.stop qui lui arrete tout mais certes ce n'est pas tres propre .

    Ou bien y aurai t'il une autre solution ?

    Merci

  9. #9
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par thecrafty Voir le message
    Ah ok il faut verifier le statut.
    Oui, si tu veux gérer proprement cela il faut vérifier le statut de temps en temps...


    Citation Envoyé par thecrafty Voir le message
    Il est donc impossible d'arreter le thread pdt l'execution de ma commande stmt.execute("LOAD DATA INFILE ..... ?
    J'ai déjà répondu à cela :
    Citation Envoyé par adiGuba Voir le message
    Maintenant la seule contrainte c'est que les méthodes bloquantes doivent gérer cela, ce dans le cas présent cela doit dépendre du driver JDBC...
    Donc sans tester tu n'auras pas la réponse...

    a++

  10. #10
    Membre expérimenté
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Par défaut gérer interruptedException
    utilise thread.interrupt() et met un "return" dans le catch (interrupted) sinon tu ignore toutes les interruptions et tu reboucles.

    démonstration avec un test unitaire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
     
    import junit.framework.Assert;
     
    import org.junit.Test;
     
    /**
     * <code>InterruptThreadTest</code>
     * Demonstration of a way to manage interruptedException.
     *
     * @author              deltree
     */
    public class TestInterruptThread implements Runnable {
     
        public boolean catched = true;
     
        /* (non-Javadoc)
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run() {
            while ( true ) {
                try {
                    synchronized ( this ) {
                        this.wait( 10000 );
                    }
                }
                catch ( InterruptedException e ) {
                    //never cancel an interrupt.
                    //see http://www.ibm.com/developerworks/java/library/j-jtp05236.html
                    System.out.println( "i was interrupted" );
                    if ( !catched ) {
                        return;
                    }
                }
            }
        }
     
        @Test
        public void testInterrupt() throws InterruptedException {
            TestInterruptThread it;
            Thread t = new Thread( it = new TestInterruptThread() );
            t.start();
            t.interrupt();
     
            Thread.sleep( 10 );
            Assert.assertTrue( t.isAlive() );
            t.interrupt();
            Thread.sleep( 10 );
            Assert.assertTrue( t.isAlive() );
            t.interrupt();
            Thread.sleep( 10 );
            Assert.assertTrue( t.isAlive() );
            t.interrupt();
            Thread.sleep( 10 );
            Assert.assertTrue( t.isAlive() );
            t.interrupt();
            Thread.sleep( 10 );
            Assert.assertTrue( t.isAlive() );
            //OK we have see that the thread is never interrupted in this way
            //Now interrupt it the right way
            it.catched = false;
            t.interrupt();
            Thread.sleep( 10 );
            Assert.assertFalse( t.isAlive() );
     
        }

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Août 2003
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 36
    Par défaut
    Envoyé par adiGuba
    Maintenant la seule contrainte c'est que les méthodes bloquantes doivent gérer cela, ce dans le cas présent cela doit dépendre du driver JDBC...
    Effectivement je vais chercher de ce coté la meme si mes esperances sont faible, merci.


    Envoyé par deltree
    utilise thread.interrupt() et met un "return" dans le catch (interrupted) sinon tu ignore toutes les interruptions et tu reboucles.
    Tu peux catcher l'InterruptedException car tu utilses un wait() mais moi j'aimerai qqchose dans le genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     @Override
        public void run() {
    ..
                try {
                    synchronized ( this ) {
                       myStatement.execute("LOAD DATA INFILE .....");
                    }
                }
                catch ( InterruptedException e ) {
                    System.out.println( "i was interrupted" );
                    if ( !catched ) {
                        return;
                    }
                }
     
        }
    et la tu as un : "Unreachable catch block for InterruptedException. This exception is never thrown from the try statement body."

    Et meme si tu magouilles en mettant ton code ( myStatement.execute(...)) dans une methode qui throws InterruptedException , ce ne rentre jamais dans le catch...

    J'ai peut etre mal compris ?

  12. #12
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    La méthode execute() ne peut pas remonter d'InterruptedException...

    a++

  13. #13
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    ... Mais elle remontera autre chose si elle est interrompue.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  14. #14
    Membre expérimenté
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Par défaut j'avais mal compris
    ... sauf si le driver est mal codé.
    c'est quel driver JDBC au juste?

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Août 2003
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 36
    Par défaut
    Citation Envoyé par deltree Voir le message
    ... sauf si le driver est mal codé.
    c'est quel driver JDBC au juste?
    C'est le driver pour MySql :com.mysql.jdbc.Driver

    Rien n'as l'air d'être remonté apres un interrupt() (j'ai fait un try{}catch Throwable...).
    Le driver ne permet pas cela ? Ou bien quelqu'un a trouvé la bonne marche a suivre (sans forcement utiliser interrupt() )?

    Merci.

  16. #16
    Membre Expert
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Par défaut
    Ce ne serait pas possible de diviser le script qui fait les insertions pour avoir une durée entre 2 scripts plus petite et pouvoir interrompre simplement le thread?

  17. #17
    Membre averti
    Profil pro
    Inscrit en
    Août 2003
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 36
    Par défaut
    Citation Envoyé par hwoarang Voir le message
    Ce ne serait pas possible de diviser le script qui fait les insertions pour avoir une durée entre 2 scripts plus petite et pouvoir interrompre simplement le thread?
    Pas evident simplement,car en fait c'est un script d'INSERT qui sera telecharger sur un server et qui peut contenir aussi bien 1000 inserts (la le traitement serai instantané) que 2millions d'inserts (là cela prend qq minutes).

  18. #18
    Membre Expert
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Par défaut
    Citation Envoyé par thecrafty Voir le message
    Pas evident simplement,car en fait c'est un script d'INSERT qui sera telecharger sur un server et qui peut contenir aussi bien 1000 inserts (la le traitement serai instantané) que 2millions d'inserts (là cela prend qq minutes).
    Si c'est acceptable, les insert pourraient etre fait par tranche, disons de 1000 et ca permettrait d'interrompre simplement le thread (et en plus de maitriser le traitement qui a été fait plutot que d'interrompre un thread et de ne pas savoir ou il en etait). Et si c'est pas acceptable... Bah faudra faire autrement

Discussions similaires

  1. Réponses: 6
    Dernier message: 15/11/2007, 12h31
  2. Réponses: 4
    Dernier message: 13/06/2007, 15h27
  3. [Sql] Comment forcer un Accent-Insensitive ?
    Par manu59 dans le forum DB2
    Réponses: 2
    Dernier message: 23/08/2005, 13h39
  4. [Struts]comment forcer un Forward ?
    Par njac dans le forum Struts 1
    Réponses: 4
    Dernier message: 13/10/2004, 15h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo