Attendre la fin d'exécution d'une méthode

Résolu
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 - 25 avril 2012 à 12:44
 sanfujinkai - 21 juin 2016 à 15:02
Bonjour,

Je ne parviens pas à faire en sorte qu'une fonction attende la fin de l'exécution de la précédente. Je m'explique.

try{
   fonctionQuiCrééUnFichier();//Cette fonction s'exécute rapidement mais le fichier créé n'est utilisable qu'au bout de 4,5 secondes.
   fonctionQuiUtiliseLeFichier();
}catch{..}


Je veux donc faire patienter l'utilisateur pendant les 4,5 secondes. Alors j'utilise Thread.sleep(4500);
Parallèlement à cette attente, j'aimerai utiliser une barre de progression pour que ce soit plus agréable pour l'utilisateur(j'utilise celle de GillesWebmaster qui est parfaite pour ce dont j'ai besoin : http://www.javafr.com/codes/EXEMPLE-UTILISATION-JPROGRESSBAR-BARRE-PROGRESSION_36496.aspx )

try{
   fonctionQuiCrééUnFichier();//Cette fonction s'exécute rapidement mais le fichier créé n'est utilisable qu'au bout de 4,5 secondes.
   barreProgress.lancementProgression();//Dure 4,5 secondes.
   Thread.sleep(4500);
   fonctionQuiUtiliseLeFichier();
}catch{..}


Le problème c'est que le sleep() freeze tout (y compris la visualisation de la barre de progression).
J'aimerai donc retirer le Thread.sleep() et faire en sorte que fonctionQuiUtiliseLeFichier() ne s'exécute QU'UNE FOIS QUE lancementProgression() est terminée.

Il semblerait que wait()/notify() puisse aider, mais je ne vois pas comment, ou mettre en place des sémaphores, ou utiliser une queue. Mais il me semble que ces 2 dernières méthodes sont un peu lourdes pour mon simple problème non ?

Merci d'avance !
A voir également:

19 réponses

cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
25 avril 2012 à 13:54
Salut,

Tu n'y arrives pas parce que tu n'utilises pas les threads :

try{
   final Thread t1 = new Thread(){
      @Override
      public void run(){
         fonctionQuiCrééUnFichier();
      }
   };
   t1.start();
   new Thread(){
      @Override
      public void run(){
         t1.join();
         fonctionQuiUtiliseLeFichier();
      }
   }
}catch{..}
3
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 2
27 avril 2012 à 11:36
Ah ! J'ai compris comment on utilisait les threads !

Ce que je veux c'est :

fonctionsA();
barreDeProgression();//Cette barre s'affiche pendant 4,5s et est INDEPENDANTE
//du reste du programme.
sleep(4500);
fonctionsB();


Le problème c'est que le sleep() endormait aussi la barreDeProgression() et donc elle s'affichait mal.

Ce qu'il fallait faire :

Thread t1{
   fonctionsA();
   barreDeProgression();
}.start();

Thread 2{
   t1.join();
   sleep(4500);
   fonctionsB();
}.start();


Pour que le sleep n'endorme pas tout ce qu'il se passe dans le thread 1.
2
sanfujinkai
21 juin 2016 à 15:02
il y a plus simple , mettre un return a la premier fonction ( return n'import quoi ).


boolean fonctionQuiCrééUnFichier(){
....
....
return True;
};



ensuite la deuxieme dois attendre la fin de la premiere fonction car il y a un return (VARIABLE na pas d'utilité a part de faire attendre l'execution car il dois le remplir avec le return de la fonction);



try{
boolean VARIBLE =fonctionQuiCrééUnFichier();
fonctionQuiUtiliseLeFichier();

.....
2
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 2
25 avril 2012 à 15:48
Oui mais comment je réalise la pause entre les threads ?

Et quand j'utilise des objets dans les Threads, j'ai une erreur "local variable var is accessed from within inner class; needs to be declared final".
   final Thread t1 = new Thread(){
      @Override
      public void run(){
         var = fonctionQuiCrééUnFichier();
      }
   };
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
26 avril 2012 à 09:30
Tu ne réalises pas de pause, la fonction .join() te permet d'attendre la fin du thread. C'est quoi var ? Ce n'était pas dans ton exemple au départ. Si tu le met en attribut de la classe, tu n'auras plus de soucis et plus besoin de la déclarer en final.
0
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 2
26 avril 2012 à 10:37
En fait mon code de départ c'est :
public class MonOutil {
    public Donnees lancement() throws IOException, Exception {

        //DECLARATIONS
        File fichierSource;
        File fichierDestination =  new File("C:\\Windows\\Temp\\nouveau.pdf");
        Donnees donnees = new Donnees();
        Progression progress = new Progression();

        try {
            //Sélection du fichier
            donnees.fichier = choisirFichier();
            System.out.println("Le fichier choisi est : " + donnees.fichier);

            //Copie du fichier et renommage
            fichierSource = new File(donnees.fichier);
            copierFichier(fichierSource, fichierDestination);
            System.out.println("C'est copié.");

            //Extraction Métadata
            extraireMetaData(fichierDestination);
            
            //progress.lance_progres(45);//Dure 4,5s.
            Thread.sleep(4500);
            donnees = lireFichier(donnees);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return donnees;
    }

    public static void copierFichier(File src, File dest) throws IOException {...}
    public static String choisirFichier() throws Exception {...}
    public static void extraireMetaData(File adresseFichier) {...}
    public static Donnees lireFichier(Donnees donnees) {...}
    }


Cette classe MonOutil me permet de récupérer des donnees, que j'envoie à mon main via : donnees = outil.lancement(); puis j'affiche les valeurs de donnees dans une JFrame.

Avec les modifications que tu m'as données, mon code devient :
    public Donnees lancement() throws IOException, Exception {

        //DECLARATIONS
        File fichierSource;
        File fichierDestination  = new File("C:\\Windows\\Temp\\nouveau.pdf");
        Donnees donnees = new Donnees();
        Progression progress = new Progression();

        final Thread t1 = new Thread() {
            //@Override

            public void run() {
                try {
                    //Sélection du fichier
                    donnees.fichier = choisirFichier();
                    System.out.println("Le fichier choisi est : " + donnees.fichier);

                    //Copie du fichier et renommage
                    fichierSource = new File(donnees.fichier);
                    copierFichier(fichierSource, fichierDestination);
                    System.out.println("C'est copié.");

                    //Extraction Métadata
                    extraireMetaData(fichierDestination);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        new Thread() {
            //@Override

            public void run() {
                try {
                    t1.join();
                    progress.lance_progres(45);//Dure 4,5s.
                    donnees = lireFichier(donnees);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        return donnees;
    }


Sauf que je reçois les erreurs suivantes :
[i]"local variable donnees is accessed from within inner class; needs to be declared final"
"local variable progress is accessed from within inner class; needs to be declared final"
"local variable fichierSource is accessed from within inner class; needs to be declared final"
"local variable fichierDestination is accessed from within inner class; needs to be declared final"/i

Je ne suis vraiment pas à l'aise avec l'encapsulation j'ai l'impression...
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
26 avril 2012 à 10:54
Fait les déclarations des attributs :

public class Machin {
    //DECLARATIONS
    private File fichierSource;
    private File fichierDestination = new File("C:\\Windows\\Temp\\nouveau.pdf");
    private Donnees donnees = new Donnees();
    private Progression progress = new Progression();

   public Donnees lancement() throws IOException, Exception {

        final Thread t1 = new Thread() {
            //@Override

            public void run() {
                try {
                    //Sélection du fichier
                    donnees.fichier = choisirFichier();
                    System.out.println("Le fichier choisi est : " + donnees.fichier);

                    //Copie du fichier et renommage
                    fichierSource = new File(donnees.fichier);
                    copierFichier(fichierSource, fichierDestination);
                    System.out.println("C'est copié.");

                    //Extraction Métadata
                    extraireMetaData(fichierDestination);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        new Thread() {
            //@Override

            public void run() {
                try {
                    t1.join();
                    progress.lance_progres(45);//Dure 4,5s.
                    donnees = lireFichier(donnees);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        return donnees;
    }

}
0
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 2
26 avril 2012 à 11:57
J'ai fait comme tu m'as dit, mais le programme n'entre pas dans le 2e run(). t1.join() semble ne pas fonctionner.
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
26 avril 2012 à 14:24
C'est normal qu'il n'entre pas dans le deuxième run et que t1.join() ne fonctionne pas, j'ai oublié de lancer le thread t2 :

Thread t2 = new Thread() {
            //@Override

            public void run() {
                try {
                    t1.join();
                    progress.lance_progres(45);//Dure 4,5s.
                    donnees = lireFichier(donnees);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
t2.start();
0
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 2
26 avril 2012 à 14:36
Ca ne fonctionne pas.
Le 2e thread se lance sans attendre que le 1er soit terminé.
Etant donné que ce que j'attends c'est que progress.lance-progres(45); soit terminé, ne peut-on pas mettre un flag/signal (comme cela se fait en C) pour indiquer au thread 2 qu'il peut se lancer ?

Parce qu'en fait j'ai l'impression que ce système de start()/join() ne permet pas de faire de pause, mais seulement de donner un ordre d'exécution aux threads.
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
26 avril 2012 à 15:03
Si tu lis la doc :

public final void join()
                throws InterruptedException

    Waits for this thread to die. 


Et j'ai testé chez moi dans un autre contexte et ca marche. Ce que tu peux faire c'est ca :

public class Machin {
    //DECLARATIONS
    private File fichierSource;
    private File fichierDestination = new File("C:\\Windows\\Temp\\nouveau.pdf");
    private Donnees donnees = new Donnees();
    private Progression progress = new Progression();

   public Donnees lancement() throws IOException, Exception {

        final Thread t1 = new Thread() {
            //@Override

            public void run() {
                try {
                    //Sélection du fichier
                    donnees.fichier = choisirFichier();
                    System.out.println("Le fichier choisi est : " + donnees.fichier);

                    //Copie du fichier et renommage
                    fichierSource = new File(donnees.fichier);
                    copierFichier(fichierSource, fichierDestination);
                    System.out.println("C'est copié.");

                    //Extraction Métadata
                    extraireMetaData(fichierDestination);
                    System.out.println("t1 termine");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        new Thread() {
            //@Override

            public void run() {
                try {
                    t1.join();
                    System.out.println("t2 commence");
                    progress.lance_progres(45);//Dure 4,5s.
                    donnees = lireFichier(donnees);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        return donnees;
    }

}


Si tu as le message t1 commence avant t2 termine, il y a bien un souci...
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
26 avril 2012 à 15:11
Je n'aime pas trop le catch(Exception e) qui nous empêche peut être de voir où est le problème...
0
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 2
26 avril 2012 à 15:17
Oui l'ordre est bien respecté.
Mais ce qu'il faudrait que le programme fasse c'est : donnees = lireFichier(donnees); ne se lance qu'à partir du moment où progress.lance_progres() est terminé.

lance_progres() est explicité dans le fichier Progression.java. Cette fonction est constituée d'un sleep() contenu dans une boucle for de telle sorte que cela dure 4,5s.
Je pense donc que ce qu'il faudrait faire c'est
1°) déplacer la ligne progress.lance_progres(45);//Dure 4,5s. dans le run du thread t1.
2°) mettre t1.join() à la fin de la boucle for de la fonction lance_progres().

Mais est-ce possible de faire en sorte que le Thread t1 de class Machin soit reconnu dans la fonction progres.lance_progres() ?
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
27 avril 2012 à 08:13
new Thread(){
@Override
public void run(){
progress.lance_progres();
}
}.start();
donnees = lireFichier(donnees);
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
27 avril 2012 à 08:16
Mais bon, ca commence à devenir un peu lourd je trouve.
0
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 2
27 avril 2012 à 09:12
Le système de thread start()/join() ne fonctionne pas.
Cela semble ne servir qu'à donner un ordre de fonctionnement.
Mais il n'y a pas moyen pour ces threads de savoir si les fonctions qu'ils utilisent sont terminées ou pas.

Ce qu'il me faudrait c'est utiliser des sémaphores du coup je pense.

public class Machin{
   //déclarations

   public Donnees lancement(){
      //Sélection du fichier
      donnees.fichier = choisirFichier();
      System.out.println("Le fichier choisi est : " + donnees.fichier);

      //Copie du fichier et renommage
      fichierSource = new File(donnees.fichier);
      copierFichier(fichierSource, fichierDestination);
      System.out.println("C'est copié.");

      //Extraction Métadata
      extraireMetaData(fichierDestination);
      progress.lance_progres(45);//Dure 4,5s.

      while(conditionSEMAPHORE){
      //Attendre tant que conditionSEMAPHORE est nul
      }
      donnees = lireFichier(donnees);
      return donnees;
   }
}

public class Progression{
   //Déclarations

   public void lance_progres(int rapidite){
      progr.go(rapidite);
   }
   
   public void go(int rap){
      //blabla
      monThread = new Thread(new MonRunnable());
      monThread.start();
   }

   public class MonRunnable implements Runnable {
      public void run() {
         for{
         //Dure 4,5 secondes
         }
         conditionSEMAPHORE = true;//SEMAPHORE disant "c'est bon tu peux y aller"
      }
   }
}


Je pense que c'est plutôt de cela dont j'ai besoin. Comment les mettre en place ?
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
27 avril 2012 à 09:58
Non, les sémaphores sont encapsulées dans la méthode join.

et d'ailleurs, les sémaphores, je fonctionnent pas comme tu le décris.

Si tu appelles une méthode comme la lecture d'un fichier dans un thread, cette méthode va ouvrir un nouveau thread et donc, tu n'attendras pas qu'elle termine. C'est ta méthode de lecture de fichier qu'il faut travailler : pour cela, il faut que la méthode de lecture de fichier soit le run d'un thread.

Mais si tu veux bricoler le mécanisme que tu décris plus haut, c'est ton choix. Pour cela, tu peux créer un fichier .LOCK à un endroit donné sur ton disque et attendre que ce fichier ait disparu pour lancer ton traitement. Il faudra que la méthode de lecture du fichier gère la création et la destruction de ce fichier.
0
Sphaxounet0 Messages postés 20 Date d'inscription mardi 30 mars 2010 Statut Membre Dernière intervention 27 avril 2012 2
27 avril 2012 à 10:10
Ce qui serait plus simple c'est d'utiliser la méthode que tu me disais plus tôt (avec les 2 threads, start() et join()) en mettant le join() à la fin du for{} de ma classe Progression.
Mais comment faire en sorte que le start() et le join() puissent "communiquer" l'un depuis la classe Machin et l'autre depuis la classe Progression ?
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
27 avril 2012 à 10:40
Ils n'ont pas besoin de communiquer.

Est ce que tu peux m'expliquer précisément ce que tu essayes de faire ?
0
Rejoignez-nous