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 :

[Thread] comment attendre la fin d'un thread?


Sujet :

Concurrence et multi-thread Java

  1. #1
    Membre confirmé Avatar de billynirvana
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2004
    Messages
    472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2004
    Messages : 472
    Points : 552
    Points
    552
    Par défaut [Thread] comment attendre la fin d'un thread?
    Bonjour,

    Voici mon problème très simple, mais je n'ai aps trouvé de solutions depuis ce matin, d'où la necessité de votre aide!

    Voici un bout de code pour commencer:

    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
     
     
    public class BlaBla {
      ...
     
      public ArrayList lancerAlgo(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil) {
        Algo algo = new Algo();
        algo.setEntrees(entrees, tailleMiniMots, tolerance, seuil);
        algo.start();
     
        // ICI IL FAUT UN TRUC!
     
        return algo.getResultats();
      }
     
      class Algo extends Thread {
        private ArrayList entrees = new ArrayList();
        private ArrayList resultats = new ArrayList();
        private int tailleMiniMots = 4;
        private int tolerance = 1;
        private int seuil = 70;
     
        public void setEntrees(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil) {
          this.entrees = entrees;
          this.tailleMiniMots = tailleMiniMots;
          this.tolerance = tolerance;
          this.seuil = seuil;
        }
     
        public ArrayList getResultats() { return resultats; }
     
        public void run() {
          int nbTask = entrees.size();
     
          vp = new VeuillezPatienter(parent, "Analyse en cours", nbTask);
     
          for(int i=0; i<entrees.size(); i++) {
            ArrayList resultatsUneEntree = traiterUneEntree((String) entrees.get(i), tailleMiniMots, tolerance, seuil);
            resultats.addAll(resultatsUneEntree);
            resultats.add(new UneReponse());
            vp.updateProgressBar(null);
          }
     
          vp.destroyProgressBar();
        }
      }

    Tout marche, ma barre de progression s'affiche correctement, mais la liste de retour est vide, car quand je fait algo.start(), ma liste est vide, d'où mon problème pour le getResultats qui est la ligne suivante.

    Je souhaiterai mettre en pause ma première méthode, afin d'attendre la fin du thread pour récupérer les résultats remplis


    Des idées?

  2. #2
    Membre habitué Avatar de Wookai
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2004
    Messages
    307
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Suisse

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2004
    Messages : 307
    Points : 180
    Points
    180
    Par défaut
    Une petite question : quel est l'intérêt d'exécuter ton algo dans un thread séparé si de toutes façons tu dois attendre la fin de la méthode dans ton thread principal ?

    Pourquoi ne pas simplement exécuter le run() comme une méthode "normale" (donc pas besoin de faire étendre Thread par Algo). Ainsi, ton return ne s'effectuera qu'une fois la méthode run() terminée !
    Wookai


  3. #3
    Membre confirmé Avatar de billynirvana
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2004
    Messages
    472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2004
    Messages : 472
    Points : 552
    Points
    552
    Par défaut
    Mon algo met quelques minutes à donner les résultats, et fige le système car il prend énormément le proceseur. En le mettant en thread avec une barre de progression, l'utilisateur pourra utiliser d'autres outils de l'application en même temps. La barre de progression affiche l'état d'avancement de l'algorithme.

    Si tu as mieux, donne moi des idées, je suis preneur!

  4. #4
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Je suis du même avis que Wookai, si juste après le start() tu attends la fin du thread, ta méthode lancerAlgo() prendra autant de temps et bloquera quand même l'affichage...

    Une solution serait d'utiliser un listener (Comment créer son propre Listener ?) :

    Ta classe Algo accepte de recevoir un Listener particulier. Ce dernier définit une méthode que tu appellera à la fin du Thread... Ainsi lancerAlgo() ne retourne aucun résultat (void) mais le Thread renseignera les objets à la fin de son traitement...


    Enfin pour la mise à jours de la JProgressBar, il est preferable d'utiliser SwingUtilities.invokeLater() de la manière suivante :
    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
    	// methode qui met a jour la JProgressBar par le processus d'evenement
    	// Pourquoi obliger l'execution de cette methode par le processus d'evenement ?
    	// -> Cf : la docs du tutoriel de Sun section : "Threads and Swing"
    	// http://java.sun.com/docs/books/tutorial/uiswing/mini/threads.html
    	public void majProgress () {
    		if ( SwingUtilities.isEventDispatchThread () ) {
    			progress.setValue (++value);
    		} else {
    			Runnable callMAJ = new Runnable () {
    				public void run () {
    					majProgress ();
    				}
    			};
    			SwingUtilities.invokeLater (callMAJ);
    		}
    	}
    Cf: FAQ: Pourquoi ma barre de progression se remplit d'un coup ?

    a++

  5. #5
    Membre confirmé Avatar de billynirvana
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2004
    Messages
    472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2004
    Messages : 472
    Points : 552
    Points
    552
    Par défaut
    Je ne comprends pas. Avant d'arriver à ce que je vous ai présenté dans le premier message, ma méthod était celle-ci:

    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
     
      public ArrayList lancerAlgo(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil) {
        ArrayList resultats = new ArrayList();
     
        if (entrees == null) return resultats;
        if (!isReady()) return resultats;
     
        int nbTask = entrees.size();
        vp = new VeuillezPatienter(parent, "Analyse en cours", nbTask);
     
        for(int i=0; i<entrees.size(); i++) {
          ArrayList resultatsUneEntree = traiterUneEntree((String) entrees.get(i), tailleMiniMots, tolerance, seuil);
          resultats.addAll(resultatsUneEntree);
          resultats.add(new UneReponse());
          vp.updateProgressBar(null);
        }
     
        vp.destroyProgressBar();
     
        return resultats;
      }
    Cette méthode fige l'application, mais me donne les résultats au bout de quelques minutes. Dans la FAQ, il est noté qu'il faut utiliser un thread, et c'est ce que j'ai essayé de faire...

    http://java.developpez.com/faq/java/...raitement_long

  6. #6
    Membre habitué Avatar de Wookai
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2004
    Messages
    307
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Suisse

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2004
    Messages : 307
    Points : 180
    Points
    180
    Par défaut
    A mon avis, voici comment du devrais faire : tu exécute ta méthode lancerAlgo comme ci-dessus, sauf que tu lance ta progress bar dans un autre thread. Ensuite, depuis ta méthode, tu mets à jour ta progress bar, soit en appelant une de ses méthodes, soit en la mettant comme listener, etc...[/b]
    Wookai


  7. #7
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Oui il faut utiliser un Thread... mais si après le start() tu bloques jusqu'à la fin du thread c'est comme si tu n'utilisais pas de thread (ta méthode lancerAlgo() prendra toujours autant de temps).

    On ne parle pas de supprimer le Thread mais de ne pas attendre sa fin...
    C'est ton thread qui renseignera le(s) composant(s) du résultat...

    a++

  8. #8
    Membre confirmé Avatar de billynirvana
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2004
    Messages
    472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2004
    Messages : 472
    Points : 552
    Points
    552
    Par défaut
    Citation Envoyé par adiGuba
    Oui il faut utiliser un Thread... mais si après le start() tu bloques jusqu'à la fin du thread c'est comme si tu n'utilisais pas de thread (ta méthode lancerAlgo() prendra toujours autant de temps).

    On ne parle pas de supprimer le Thread mais de ne pas attendre sa fin...
    C'est ton thread qui renseignera le(s) composant(s) du résultat...

    a++
    Les résultats je veux les afficher quand l'algo est terminé, mais en meme temps sans figer le système... L'interet du thread est que pendant ce temps là, il peut modifier le JTree, qui est un autre objet manipulable de mon application. Or le problème est que je ne sais pas quand mon thread se termine.

    L'idée est donc que quand mon Thread a fini son boulot, il fait signe à la classe BlaBla que l'algo a pris fin. OK. Je l'avais déjà fait à travers une variable. Mais la classe ToTo (cf plus bas) attend le résultat de la méthode lancerAlgo(). Et donc cela ne sert à rien. Et je suis perdu!!!!!!!!!

    En reprenant ce que j'avais commencé à faire,

    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
     
    public class BlaBla { 
      ... 
     
      public ArrayList lancerAlgo(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil) { 
        Algo algo = new Algo(); 
        algo.setEntrees(entrees, tailleMiniMots, tolerance, seuil); 
        algo.start(); 
     
        // ICI IL FAUT UN TRUC! 
     
        return algo.getResultats(); 
      } 
     
      class Algo extends Thread { 
        private ArrayList entrees = new ArrayList(); 
        private ArrayList resultats = new ArrayList(); 
        private int tailleMiniMots = 4; 
        private int tolerance = 1; 
        private int seuil = 70; 
     
        public void setEntrees(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil) { 
          this.entrees = entrees; 
          this.tailleMiniMots = tailleMiniMots; 
          this.tolerance = tolerance; 
          this.seuil = seuil; 
        } 
     
        public ArrayList getResultats() { return resultats; } 
     
        public void run() { 
          int nbTask = entrees.size(); 
     
          vp = new VeuillezPatienter(parent, "Analyse en cours", nbTask); 
     
          for(int i=0; i<entrees.size(); i++) { 
            ArrayList resultatsUneEntree = traiterUneEntree((String) entrees.get(i), tailleMiniMots, tolerance, seuil); 
            resultats.addAll(resultatsUneEntree); 
            resultats.add(new UneReponse()); 
            vp.updateProgressBar(null); 
          } 
     
          vp.destroyProgressBar(); 
        } 
      }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public class ToTo { 
      ... 
      Arraylist Resultats = blable.lancerAlgo(...);
      afficher(Resultats);
    }

    To AdiGulba:
    Désolé, je n'ai pas compris la fin de ta réponse.


    Cordialement,


    Billy

  9. #9
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par billynirvana
    To AdiGulba:
    Désolé, je n'ai pas compris la fin de ta réponse.
    C'est pas grâve

    En fait tu ne peux pas attendre le retour de ta méthode lancerAlgo(), car :
    • Soit tu retournes null car le Thread n'est pas fini.
      Soit tu dois attendre la fin du Thread et le Thread est alors inutile...


    La meilleure solution c'est que ce soit le Thread qui appelle la méthode afficher(Resultats); de ToTo lorsqu'il a terminé. Ainsi, tu lances le Thread et tu continues à faire autre chose pendant ce temps... et lorsque le thread est terminer tu met à jours l'affichage. Par 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
    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
    public class BlaBla {
      ...
     
      public void lancerAlgo(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil, ToTo toto) {
        Algo algo = new Algo(toto);
        algo.setEntrees(entrees, tailleMiniMots, tolerance, seuil);
        algo.start();
      }
     
      class Algo extends Thread {
        private ArrayList entrees = new ArrayList();
        private ArrayList resultats = new ArrayList();
        private int tailleMiniMots = 4;
        private int tolerance = 1;
        private int seuil = 70;
        private ToTo toto ;
     
        public Algo(ToTo toto) {
    		this.toto = toto;
        }
     
        public void setEntrees(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil) {
          this.entrees = entrees;
          this.tailleMiniMots = tailleMiniMots;
          this.tolerance = tolerance;
          this.seuil = seuil;
        }
     
        public ArrayList getResultats() { return resultats; }
     
        public void run() {
          int nbTask = entrees.size();
     
          vp = new VeuillezPatienter(parent, "Analyse en cours", nbTask);
     
          for(int i=0; i<entrees.size(); i++) {
            ArrayList resultatsUneEntree = traiterUneEntree((String) entrees.get(i), tailleMiniMots, tolerance, seuil);
            resultats.addAll(resultatsUneEntree);
            resultats.add(new UneReponse());
            vp.updateProgressBar(null);
          }
     
          // Mise à jours de l'affichage
          toto.afficher(resultats);
     
          vp.destroyProgressBar();
        }
      }

    Maintenant tu peux améliorer cela en utilisant un listener (cf la faq), ce qui permet :
    • D'informer plusieurs objets du résultats du thread (du moment qu'ils implémentent le listener).
      D'ignorer le type réel de l'objet (dans ce cas seul la classe ToTo peut être utilisée).


    a++

  10. #10
    Membre confirmé Avatar de NeptuS
    Profil pro
    Inscrit en
    Août 2005
    Messages
    392
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Août 2005
    Messages : 392
    Points : 508
    Points
    508
    Par défaut ouai ouai ouai ....
    Bon heuu .. t'as essayé de faire 1 recherche sur le forum pour la réponse à ta question ? La réponse est sur le site : 3e lien sur la page de recherche (chaine recherchée : "attendre Thread")... enfin bon ....

    1- Effectivement, comme tout le monde se tue à te le dire, le Thread est utilisé pour effectuer une action en parallèle (en apparence) de l'application principale. La seule action qui nécessite une action parallèle ici est l'affichage de ta JProgressBar .... mais bon .. soit ... et pourquoi pas faire exécuter ce Thread par une autre machine ? tu sais, la véritable et seule solution pour libérer du temps processeur c'est de prendre les tâches qui l'occupent et de les renvoyer ailleur.... cherche du côté Socket/ServerSocket ou de la P.E.R. ....

    2- Perso, un traitement qui dure plus de ...... plus du temps qu'il faut pour expliquer ce qu'il fait , C 1 mauvais traitement .... alors regarde aussi un peu de ce côté là .... Vérifie que ton algo est optimisé .... vérifie que les objets que tu manie ne sont pas trop lourds ... que tu ne charge plus d'infos que ce dont tu as besoin pour ton traitement ..... et enfin, une fois que t'as vérifié tout ça, essaye de charger en mémoire tes infos AVANT d'effectuer le traitement (si le volume est devenu raisonnable). Un utilisateur s'attend plutot à avoir un temps important de chargement au début d'une application (ça donne l'impression d'avoir affaire à 1 super logiciel 8) ) plutôt que pendant son exécution (ça donne l'impression d'un logiciel buggué )

    3- J'avoue .. je parle sans avoir lu ton algo .... mais tu peux pas essayer d'afficher dans un coin un "Traitement en cours", tout en affichant tes résultats au fur et à mesure qu'ils arrivent ? Si il y a un traitement spécifique à l'objet résultat (comme un double-clic sur une case d'1 JTable par exemple) n'oublie pas dans ce cas de stopper ton Thread.


    Bon aller ... sur ce fourmillement de bonnes (et mauvaises) idées ... jte laisse te renseigner / tester / choisir (ouaip, dans l'ordre) la solution que tu va adopter. Bopn courage pour la suite.
    Toute vérité est bonne à entendre, même si toutes les vérités ne sont pas bonnes à dire.
    Rien ne sert de partir à point, il vaut mieux courir .

  11. #11
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Hum certes mais certains traitements lourds comme des requêtes à une BD, à un gros site web, un calcul long (ex simul scientifique qui dure plusieurs heures), une impression de plusieurs dizaines de pages ou tout simplement l'écriture d'un gros fichier de qq centaines de Mo ne peuvent pas toujours être déférés sur d'autres machines ou au moment du chargement. Et évidement l'utilisateur simple ne veut qu'une chose : savoir si son programe a planté ou pas... Une seule facon de faire : mettre à jour la GUI de temps à autre pour montrer que le prog vit encore. Il est donc oblige de lancer sa tâche dans une autre thread puisque s'il reste dans celle de Swing la GUI sera completement bloquée pendant tout le temps de la requête.

    Un truc comme ca "devrait" marcher (du moins dans son principe):

    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
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
     
    public class BlaBla {
      //...
     
      public ArrayList lancerAlgo(ArrayList entrees, int tailleMiniMots,
                                  int tolerance, int seuil, AlgoObserver observer) {
        Algo algo = new Algo();
        algo.setEntrees(entrees, tailleMiniMots, tolerance, seuil);
        // Configure l'observateur si necessaire.
        if (observer != null) {
          int stepNumber = algo.getStepNumber();
          observer.setTaskLength(stepNumber);
        }
        // Demarre la requete dans une thread separee.
        if (observer != null) {
          algo.start();
          // retourne null.
          // Un autre idee est de retournee algo.getResultats qui sera remplie au fur et a mesure par la thread.
          // La liste agissant comme une valeur proxy initialement vide.
          // De cette maniere le programme a deja un reference sur cette liste-la quand on demanderra la mise-a-jour tout a la fin.
          // cf voir la classe/Interface ImageObserver qui retourne une image vide qui est mise-a-jour au fur et a mesure pendant le telechargement..
          return null;
        }
        // Pas d'observateurs fourni.
        // Alors on bloque jusqu'a la recuperation complete de la requete.
        return algo.findResult();
      }
     
      private class Algo
          extends Thread {
        private ArrayList entrees = new ArrayList();
        private ArrayList resultats = new ArrayList();
        private int tailleMiniMots = 4;
        private int tolerance = 1;
        private int seuil = 70;
        private AlgoObserver observer = null;
     
        public Algo() {
          super();
          // Car sinon la thread prend la priorité de la thread dans laquelle elle est créée (probablement celle de Swing)
          // Ce qui n'est pas toujours désirable.
          setPriority(Thread.NORM_PRIORITY);
        }
     
        // Pourrait etre fait dans le constructeur.
        public void setEntrees(ArrayList entrees, int tailleMiniMots, int tolerance,
                               int seuil, AlgoObserver observer) {
          this.entrees = entrees;
          this.tailleMiniMots = tailleMiniMots;
          this.tolerance = tolerance;
          this.seuil = seuil;
          this.observer = observer;
        }
     
        // Retourne la duree approximative de la tache en fonction des parametres entres.
        public int getStepNumber() {
          return entrees.size();
        }
     
        public ArrayList getResultats() {
          return resultats;
        }
     
        // Fait le vrai travail.
        public ArrayList findResultats() {
          int nbTask = entrees.size();
          for (int i = 0; i < entrees.size(); i++) {
            ArrayList resultatsUneEntree = traiterUneEntree( (String) entrees.get(i),
                tailleMiniMots, tolerance, seuil);
            resultats.addAll(resultatsUneEntree);
            resultats.add(new UneReponse());
            if (oberver != null) {
              observer.taskUpdated(i, null);
            }
          }
          if (observer != null) {
            observer.endOfTask(resultats);
            observer = null;
          }
          return resultats;
        }
     
        // On appelle just findResult() mais l'execution est dans une thread separee.
        @Override public void run() {
          findResultats();
        }
      }
     
      // Un observateur (kifkif avec listener) sur la requete.
      private class AlgoObserver {
        private VeuillezPatienter vp;
     
        public AlgoObserver(Container parent) {
          vp = new VeuillezPatienter(parent, "Analyse en cours", 0);
        }
     
        public void setTaskLength(int lengt) {
          vp.setTaskLength(length);
        }
     
        // cette methode sera appelle stepNumber fois.
        public void taskUpdated(int step, String message) {
          final int s = step;
          final String msg = message;
          // Important car les composants de Swing ne sont pas Thread-safe.
          SwingUtilities.invokeLater(new Runnable() {
            @Override public void run() {
              vp.updateProgressBar(s, msg);
              //Eventellement ont peut aussi mettre a jour une partie de l'affichage princpal ici si on a deja une reference sur la liste (voir proxy).
            }
          });
        }
     
        // Le passage des resultats en parametre est inutile si on a utilise une liste proxy (dans ce cas lancer algo ne retourne jamais null).
        public void taskDone(ArrayList resultats) {
          final ArrayList r = resultats;
          // Important car les composants de Swing ne sont pas Thread-safe.
          SwingUtilities.invokeLater(new Runnable() {
            @Override public void run() {
              vp.destroyProgressBar();
              vp = null;
              // Ici mettre a jourt ou creer les composants necessaires à l'affichage des resultats dans la fenetre principale.
              //affichage.updateAfterQuery();
              affichage.updateAfterQuery(r);
            }
          });
        }
      }
    }
    Comme indiqué plus haut mieux vaut mettre à jour les composants de Swing en utilisant SwingUtilities.invokeLater(). En effet, surtout sur les composants complexe comme les tables et les arbres, tu peux t'attendre à une jolie exception si ton code de mise-à-jour du composant a le malheur d'être executé pile-poil au moment où l'interface est entrain de se redessiner.

    Il est également possible de rajouter une méthode de gestion d'erreur dans l'observateur genre taskFailed() associee a un bloc try{...}catch{...} dans findResultats().

    Hum j'espere ne pas avoir écrit trop de betises moi je suis un peu malade aujourd'hui...

    Edit - Swing a deja une classe similare a ta classe VeuillezPatienter il s'agit de javax.swing.ProgressMonitor
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  12. #12
    Membre confirmé Avatar de billynirvana
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2004
    Messages
    472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2004
    Messages : 472
    Points : 552
    Points
    552
    Par défaut
    D'abord, merci à vous tous d'avoir pris votre temps pour moin problème, qui est d'ailleurs résolu.


    à NeptuS:
    J'ai fais une recherche à travers le forum et la FAQ, et je m'en suis servi avant de poster ce topic. A la fin, je pensais que mon problème était un peu différent...

    J'ai pris l'idée d'AdiGulba, bien que celle de bouye m'interesse. Je n'ai pas encore mis de listener pour le moment, j'ai passé en paramètres la classe mère.


    Voici donc pour les futurs interessés ce que j'ai implémenté comme code:

    FenetreTests est la classe mère. C'est une fenetre interne à mon application principale. [style MDI]
    Ici, j'ai utilisé un menu qui permet d'initialiser les tests (montée en mémoire des ressources necessaires), et de lancer l'algo. Les ressources necessaires sont l'oeuvre d'autres topics concernant les fameuses étoiles dans les expressions régulières. . Une autre action du menu consiste à lancer l'algorithme lui même.

    Ici, on va me lyncher sur comment je traite les actions du menu. Je sais qu'il faut faire differement!


    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
     
    public class FenetreTests extends JInternalFrame implements ActionListener {
       ...
      public void actionPerformed(ActionEvent e) {
        String source = ((AbstractButton) e.getSource()).getText();
        ...
        if (source.equals("Initialiser les tests")) {
          // fenetre est une autre JInternalFrame comportant le JTree
          // grammaire est la classe qui éxpand les expressions régulières.
          stage = new Stage(parent, this, grammaire);
          stage.insererRessources(fenetre.sauverNoeuds(fenetre.getNoeudParent()));
          stage.start();
        }
     
        if (source.equals("Ouvrir un fichier de tests...")) {
        // Ici, j'ouvre un fichier avec un JFileChooser, et je remplis ligne par ligne une liste de nom entrees.
        ...
        stage.lancerAlgo(entrees, tailleMiniMots, tolerance, seuilAcceptation);
        ...
      }
     
      ...
     
      public void afficherResultats(ArrayList resultats) {
        // exprimerLesResultats est une méthode qui va afficher les résultats de manière plus jolie
     
        String res = "";
        ArrayList resultatsExprimees = exprimerLesResultats(resultats);
     
        if (resultatsExprimees != null) {
          int nbRes = resultatsExprimees.size();
     
          for(int i=0; i<nbRes; i++)
            res += (String) resultatsExprimees.get(i) + "\n";
        }
     
        addMessage(res);
      }
      ...
    }

    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
     
    public class Stage extends Thread {
      private JFrame parent = null;
      private FenetreTests fenetreTests = null;
      private Grammaire grammaire = null;
      private VeuillezPatienter vp;
     
     
      public Stage(JFrame parent, FenetreTests fenetreTests, Grammaire grammaire) {
        this.parent = parent;
        this.fenetreTests = fenetreTests;
        this.grammaire = grammaire;
     
        ready = false;
      }
     
      public void run() {
        // Cette fonction va inserer les ressources. En moyenne cela prend 30s à 1min, d'où ce thread.
        ... 
        int nbTasks = ressources.size();
        vp = new VeuillezPatienter(parent, "Insertion des ressources...", nbTask);
        ...
        for(,,) { ... vp.updateProgressBar(null); ... }
     
        vp.destroyProgressBar();
     
        ready = true;
     
        System.out.println("Construction de la liste des descripteurs terminée.");
      }
     
      ...
     
     public void lancerAlgo(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil) { 
        Algo algo = new Algo(entrees, tailleMiniMots, tolerance, seuil); 
        algo.start(); 
      }
     
      class Algo extends Thread { 
        private ArrayList entrees = new ArrayList(); 
        private int tailleMiniMots = 4; 
        private int tolerance = 1; 
        private int seuil = 70; 
     
        public Algo(ArrayList entrees, int tailleMiniMots, int tolerance, int seuil) { 
          this.entrees = entrees; 
          this.tailleMiniMots = tailleMiniMots; 
          this.tolerance = tolerance; 
          this.seuil = seuil; 
        } 
     
        public void run() { 
          // Cet algo dépend de la taille du fichier, mais une ligne prend en moyenne 2 secondes...
     
          int nbTask = entrees.size(); 
     
          vp = new VeuillezPatienter(parent, "Analyse en cours", nbTask); 
     
          for(int i=0; i<entrees.size(); i++) { 
            ArrayList resultatsUneEntree = traiterUneEntree((String) entrees.get(i), tailleMiniMots, tolerance, seuil); 
     
            // l'affichage au fur et à mesure montre aussi au client que cela n'a pas planté
            fenetreTests.afficherResultats(resultatsUneEntree);
            fenetreTests.afficherResultats(null); 
     
            vp.updateProgressBar(null); 
          }
     
          vp.destroyProgressBar(); 
        } 
      }
     
      ...
    }

    Mon algorithme prend du temps, et je crains ne pas pouvoir l'optimiser à fond.


    Cordialement,


    Billy

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment attendre la fin de Message entre thread
    Par grunk dans le forum Android
    Réponses: 5
    Dernier message: 11/07/2011, 17h01
  2. [QThread] Comment attendre une information d'un thread dans le thread principal ?
    Par f.denis dans le forum Multithreading
    Réponses: 5
    Dernier message: 15/04/2010, 11h57
  3. Attendre la fin d'un thread
    Par apmic dans le forum EDT/SwingWorker
    Réponses: 8
    Dernier message: 23/08/2007, 10h04
  4. Attendre la fin d'un thread: Access violation
    Par Booster2ooo dans le forum Delphi
    Réponses: 5
    Dernier message: 15/04/2007, 10h31
  5. [thread]attendre la fin d'un thread?....
    Par babarpapa dans le forum Concurrence et multi-thread
    Réponses: 9
    Dernier message: 29/03/2006, 14h31

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