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 !:
'-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.
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); } ... ... ... } } }
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.
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.
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); .... } .... }
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.
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.
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); } } } }
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.
Partager