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

Concurrence et multi-thread Java Discussion :

Arrêter / Stopper un groupe de Threads ou ThreadGroup


Sujet :

Concurrence et multi-thread Java

  1. #1
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    80
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Mars 2006
    Messages : 80
    Points : 41
    Points
    41
    Par défaut Arrêter / Stopper un groupe de Threads ou ThreadGroup
    Bonjour,

    J'ai déjà fait quelques recherches à ce sujet sur le forum mais rien de bien concluant concernant mon cas finalement, je vais donc vous embêter avec l'arrêter d'un grand nombre de threads via ThreadGroup (il paraît que c'est la bonne solution...)

    Donc voilà, je développe une application Client-Serveur, de monitoring de DB. Mon serveur crée un thread pour chacune des DB (il y en à 324), et ces thread fond des test de connexion et des SELECT archi simple pour voir si les DB sont toujours up ou pas.

    Voici comment j'ai organisé ça côté serveur:

    Classe ServeurThread , ma Classe Serveur !:

    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
     
    public class ServeurThread 
    {...
      public static ThreadGroup thG;
      public static String ThreadConnexionGroup="ThreadConnexion";
      ...
       try 
       {
        ...
        thG = new ThreadGroup("root");
                  threadCo = new ThreadConnexion(verbose,log,ThreadConnexionGroup,thG); //on instancie l'objet qui fait les traîtements
                  threadCo.start();
     
    //ThreadConnexion s'occupera de créer un thread pour chaque DB. Verbose et  log sont des boolean qui me servent à définir si je dois écrire à un moment ou un autre dans un fichier texte, rien de bien util pour ce qui me pose problème en somme.
     
        while (true) //boucle infinie
        {
             ...
             Socket connexion = service.accept();
             ...
             if(options.contains("u"))
                        {
                            current = getStatusTime();
                            sortie.println("$$----------HICT217 Application Stopped at "+current+"----------");
                            //System.exit(0);
                            thG.interrupt();
                            System.exit(0);
                        }
              ... ... ...
         }
       }
    }
    '-u' est l'option à taper quand on souhaite arrêter tout les threads. Jusqu'a la semaine passée, comme ThreadConnexion est enfant de ServeurThread, je me disais qu'un bête System.exit(0) suffirait à tuer l'application et tout ses enfants, comme de fait, sauf que pour les DB MySQL, tuer sauvagement des connexion crée des warnings qui dérangent fort mon boss . Donc ça fonctionne mais c'est pas propre.
    J'ai donc décidé de suivre les conseils que j'avais demandé ici même, sur ce forum, il y a quelques mois, et d'utiliser les ThreadGroup.
    D'où mon thG.interrupt();
    Mais avant de continuer je vais vous montrer le code de mes 2 autres classes.

    ThreadConnexion, qui va se charger de consulter une DB, et pour chaque nom de DB qu'elle va trouver dans une table, elle va rechercher les informations de connexion concernant cette DB et créer un thread qui va monitorer la dite DB.

    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
     
    public class ThreadConnexion extends Thread 
    {
        ...
        String ThreadConnexionGroup="ThreadConnexion";
        ...
        public ThreadConnexion(boolean verbose,boolean log,String ThreadConnexionGroup, ThreadGroup thG)
      {
          super(thG,ThreadConnexionGroup);
          ...
          try
          {
            //on crée les flux qui seront utilisés pour écrire dans le fichier de logs.
            fw = new FileWriter(fileAdress, true);
            output = new BufferedWriter(fw);
          }
          catch (IOException IOe)
          {...
          }
      }
     
        public void select2(String db_name,String DB_type)
        {
        ....
        try 
    	{
        ...
        ThreadChild tc = new ThreadChild(db_name,suburl,sublogin,subpasswd,DB_type,driver,DB_type2,waitTime2,ThreadConnexionGroup,ServeurThread.thG);
        ....
            }
        ....
        }
    Select2 est instancié dans une boucle autant de fois que le nombre de records trouvé dans la table qui contient le nom des DB à monitorer.
    Pas d' .interrupt() de Thread dans cette classe...

    ThreadChild sont les Thread qui vont se connecter directement aux DB à monitorer et faire des test de connexion + selects simplistes sur ces DB.

    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
     
    public class ThreadChild extends Thread
    {
        public ThreadChild(String db_name,String suburl, String sublogin, String subpasswd, String db_type,String driver,String DB_type2,int waitTime,String ThreadChildGroup, ThreadGroup thG) 
        {
            super(thG,ThreadChildGroup);
            this.db_name = db_name;             //-->Contient le nom de la base de donnée  
            this.suburl=suburl;                 //-->Contient l'url de la DB cible  
            this.sublogin=sublogin;             //-->Contient le login de connexion à la DB cible
            this.subpasswd=subpasswd;           //-->Contient le password de connexion à la DB cible
            this.db_type=db_type;               //-->Contient la requête Select à exécuter par le Thread sur la DB
            this.driver=driver;                 //-->Contient le nom du driver (String) JDBC à loader par le Thread
            this.DB_type2=DB_type2;
            this.waitTime=waitTime;
        }
     
        ...
        public void run()
        {
            int i=0; 
            boolean fin = false;
            //boolean conn;
            boolean conn;
            boolean boolTest = true, outRun = false;
     
    	try 
    	{
                boolean continu = true;
                while(continu/*i<40*/)  //Run the query
                {
                    conn = connexionDB();
                    if(conn==false && boolTest==true)
                    {
                        boolTest=true;
                        //la DB n'a plus été down depuis longtemps, mais maintenant elle est down depuis...
                        sleep(waitTime);
                        connexionDB();
                    }
                    else if(conn==true && boolTest==false)
                    {
                        boolTest=true;
                    }
     
     
                    while(conn==false)
                    {
                        sleep(waitTime);
                        connexionDB();
                    }
                    select(db_type);  //Exécute la requête qui est passée en paramètre au Thread.
                    //Si la requête renvoie une réponse, ça veut dire que la DB est toujours up
                    //Dans le cas où on à pas de réponse, la DB est down, déclencher une exception
                    //et être averti que la DB est down.
                    con.close();
                    sleep(waitTime);
                    Thread.yield();
                    //i++;
                }
                outRun = true;           
    	    ServeurThread.thG.interrupt();
                synchronized(this) 
                {
                    Thread.yield();
                    // lecture du boolean 
                    continu = this.stopThread;
                } 
            }
    	catch (InterruptedException e)
    	{
     
                System.out.println("Run Interrupted: " + e +" "+db_name);
                currentThread().interrupt(); // very important
                if(!outRun)
                {
                    ThreadConnexionLoad tcl = new ThreadConnexionLoad(db_name,suburl,sublogin,subpasswd,db_type,driver,DB_type2,waitTime);
                    System.out.println("et je recharge un nouveau thread..."+db_name);
                    tcl.start();
                }
                System.out.println("");
            }
            catch (SQLException e2)
            {
                System.out.println("Connxion close failed on DB: "+db_name);
                System.out.println("Exception: "+e2);
            }        
            finally
            {
                try
                {        
                    System.out.println("Je fais le connexion.close() " + db_name);
                    con.close();
                }
                catch(SQLException e2)
                {
                    System.out.println("Connxion close failed on DB: "+db_name);
                    System.out.println("Exception: "+e2);
                }        
            }
        }
    }
    Au moment où je recharge le thread, c'est juste parce que c'est une appli de monitoring, et que si jamais un thread tombe, faut le recréer car une DB doit toujours être monitorée. Normalement, le flag outRun ne passe à true que si un problème autre qu'une InterruptedException arrive, dans ce cas le thread doit être relancé, voilà pour explication.

    Mon problème dans MySQL est qu'en coupant sauvagement l'application des "connexion aborted" sont générés, donc je me suis dit que c'est parce que la connexion à la DB était mal fermée, pas explicitement du moins (System.exit(0)...), donc je mettrais un bloc Finally dans le bas de mon run, et je ferme explicitement la connexion con.

    Un bloc Finally est censé TOUJOURS s'exécuter. Mais faut croire que non, le System.exit(0) est plus balaise dans certains cas, pas toujours, et de manière aléatoire, c'est très bizarre et dérangeant.

    Donc bon, voilà, j'aimerais que quand mon ServeurThread reçoit un '-u', il tue mes thread proprements et de même pour les connexions (fermées par les threads enfants).

    Est-ce que j'utilise bien mes ThreadGroup ? (de toute évidence non puisque ça merde) Comment on ajoute dans un ThreadGroup alors ? Comme je dois me débrouiller avec mes Interrupt pour fermer des connexion ? Pourquoi parfois mon bloc Finally n'est-il pas exécuté ?

    Beaucoup de question dont j'ai du mal à trouver les réponses sur internet.

    D'avance Merci.
    Bien à vous.

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Salut, d'abord, j'avoue, j'ai pas tout lu en détails, mais il me semble que tu n'a pas bien lu la doc de Interrupt() et tu as cru qu'elle arrêtait d'office le Traitement d'un Thread. Celle-ci stipule clairement que
    1) elle positionne le flag 'isInterrupted' à true
    2) "Eventuellement" si tu es dans un IO ou d'autres conditions particulières (wait, sleep, ...), déclenche une méthode InterruptedException. Ce qui ne veux pas dire que tes connections SQL vont laisser ce interruptedException remonter non plus

    Conclusion:
    Base toi sur le flag interrupted seulement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    while(!isInterrupted()){
     // opération du Thread
    }
    if (isInterrupted(){
    // Fin du thread, nettoyage
    // Vive la retraite
    }
    Le catch (InterruptedException), n'est à faire que si tu utilise des méthodes qui déclarent explicitement renvoyer cette exception.

    Note que beaucoup de chose peuvent appeler interrupt su un Thread, et il est possible que tes libraries en interne l'utilisent. Donc je te conseille, en sus, d'ajouter un flag "à toi" dans le Thread, que tu check aussi

  3. #3
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    80
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Mars 2006
    Messages : 80
    Points : 41
    Points
    41
    Par défaut
    Oki, merci beaucoup pour ces précisions, je dois avoir mal lu effecivement.

    Mais je croyais sincèrement (et selon ma logique) que je pouvais facilement déclencher une interruptedException via Interrupt() puis mettre le connexion.close() dans le bloc Finally...

    Je vais revoir mon code.
    Merci ^^

    Cher lecteur de ce topic, si tu as une autre idée, je suis ouverts à toutes les propositions ( hum...)

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2007
    Messages : 132
    Points : 170
    Points
    170
    Par défaut
    Faire un System.exit pour arrêter ton application n'est vraiment pas une bonne solution.

    Car normalement tu ne sors pas de l'appel System.exit

    Une solution est de rajouter une méthode dans tous tes threads pour stopper ton application de facon propre. Cette fonction indiquerait au thread qu'il doit se terminier et closerai la connection en cours. Ou alors comme l'a écrit tchize_ de tester si le trhead a été interrompu.

    Ton thread principal doit attendre patiemment ou avec un timeout la fin de tous les threads.

    Remarque:
    si tu utilises un boolean pour savoir si un thread doit continuer ou pas il faut que ce boolean soit volatile.

  5. #5
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    80
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Mars 2006
    Messages : 80
    Points : 41
    Points
    41
    Par défaut
    Quand on ajoute un Thread parent à un groupe, les threads enfants font-ils parties du même groupe par défaut ?

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Un thread est associé à un groupe à sa création. Par défaut, il hérite du groupe de celui qui l'a créé.

Discussions similaires

  1. [JMeter] Utilisation d'un groupe de threads
    Par Pandev31000 dans le forum Tests et Performance
    Réponses: 2
    Dernier message: 10/02/2012, 11h54
  2. Synchronisation de groupe de threads
    Par millie dans le forum Concurrence et multi-thread
    Réponses: 0
    Dernier message: 08/04/2008, 11h38
  3. Arrêter / Stopper un Thread défini
    Par ouranos21 dans le forum Concurrence et multi-thread
    Réponses: 6
    Dernier message: 30/01/2008, 14h25
  4. Arrêter les routines dans un thread
    Par Steff2 dans le forum Composants VCL
    Réponses: 4
    Dernier message: 21/08/2007, 15h27
  5. [java.util.Timer]Comment arrêter l'exécution d'un Thread
    Par Invité dans le forum Concurrence et multi-thread
    Réponses: 1
    Dernier message: 07/06/2006, 07h54

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