Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème thread et communication entre classe

    23 novembre 2014 à 20:58:18

    Bonjour,

    Je tente de me mettre aux thread en Java.
    Dans le projet, je doit créer des producteurs (chaque producteur doit incrémenter un compteur) qui remplisse le grenier.

    * J'ai un problème de communication entre les différentes classes de mon projet (je ne sais pas comment modifier mon grenier via les thread)

    * Je ne suis pas sure que mes threads fonctionne (actuellement il doit juste afficher des chiffres et je n'ai rien dans la console)

    * Je dois pouvoir ajouter autant de producteur que je veux en cliquant sur un bouton via la classe MainView

    Actuellement je créé automatiquement un producteur au démarrage de MainView et un thread qui est censé m'afficher des données dans la console. Ca ne fonctionne pas.

    Pouvez-vous:

    - me dire si mon thread est bien construit et comment communiquer avec la classe grenier (je suis en echec sur ca)
    - me guider ou me montrer comment créer autant de producteur que je veux via le bouton dans la MainView.

    Un grand merci

    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    package consommateur;
    
    /**
     *
     * @author Romain
     */
    public class Launcher {
    
        /**
         * @param args the command line arguments
         */
        
        public static void main(String[] args) {
            // TODO code application logic here
            MainView MV = new MainView();
            MV.setVisible(true);        
            
            Producteur ProdModel = new Producteur();
            ConsommateurModel ConsoModel = new ConsommateurModel();
            
        }
        
    }
    
    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    package consommateur;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import javax.swing.BoxLayout;
    import javax.swing.ImageIcon;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    
    /**
     *
     * @author Romain
     */
    public class MainView extends JFrame {
        public MainView(){
            /***** Définition JFrame principal ******/
            this.setTitle("Consommateur  VS Producteur");
            this.setMinimumSize(new Dimension(800,500));
            this.setMaximumSize(new Dimension(1100,1000));
            this.setLocationRelativeTo(null);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
                   
            /****** JMenuBar ******/
            JMenuBar MainBar = new JMenuBar();
            JMenu Option = new JMenu("Option");
            Option.setMnemonic(KeyEvent.VK_F);
            ImageIcon IconeExit = new ImageIcon(getClass().getResource("icons/door_out.png")); 
            ImageIcon IconeAddConso = new ImageIcon(getClass().getResource("icons/user_green.png"));
            ImageIcon IconeAddProd = new ImageIcon(getClass().getResource("icons/user_orange.png"));
            
            JMenuItem ExitMenuItem = new JMenuItem("Quitter", IconeExit);
            ExitMenuItem.setMnemonic(KeyEvent.VK_E);
            ExitMenuItem.setToolTipText("Quitter l'application");
            ExitMenuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent event) {
                    System.exit(0);
                }
            });
            
            JMenuItem AddProdMenuItem = new JMenuItem("Ajouter producteur", IconeAddProd);
            AddProdMenuItem.setMnemonic(KeyEvent.VK_P);
            AddProdMenuItem.setToolTipText("Ajouter un producteur");
            AddProdMenuItem.addActionListener(new ActionListener (){
                @Override
                public void actionPerformed(ActionEvent event) {
                    
                }
            });
            
            JMenuItem AddConsoMenuItem = new JMenuItem("Ajouter consommateur", IconeAddConso);
            AddConsoMenuItem.setMnemonic(KeyEvent.VK_C);
            AddConsoMenuItem.setToolTipText("Ajouter un consommateur");
            AddConsoMenuItem.addActionListener(new ActionListener (){
                @Override
                public void actionPerformed(ActionEvent event) {
                    
                }
            });
            
            Option.add(AddProdMenuItem);
            Option.add(AddConsoMenuItem);
            Option.add(ExitMenuItem);
            MainBar.add(Option);   
            this.setJMenuBar(MainBar);
            
            /****** JPanel Racine *******/
            JPanel MainPanel = new JPanel();
            /*** Subdivision du JPanel ***/
            JPanel ProdPanel = new JPanel();
            JPanel GrenierPanel = new JPanel();
            JPanel ConsoPanel = new JPanel();
            
            //FlowLayout experimentLayout = new FlowLayout();
            MainPanel.setLayout(new GridLayout(1,3));
            
            
            ProdPanel.setBackground(Color.red);
            ProdPanel.setVisible(true);
            ProdPanel.setLayout(new BoxLayout(ProdPanel, BoxLayout.PAGE_AXIS));
            
            GrenierPanel.setBackground(Color.green);
            GrenierPanel.setVisible(true);
            
            GrenierView GrenierMainView = new GrenierView();
            GrenierPanel.add(GrenierMainView);
            GrenierMainView.setVisible(true);
              
            
            ConsoPanel.setBackground(Color.blue);
            ConsoPanel.setVisible(true);
            
            MainPanel.add(ProdPanel);
            MainPanel.add(GrenierPanel);
            MainPanel.add(ConsoPanel);
            
            this.setContentPane(MainPanel);
            
            ProducteurView newprob = new ProducteurView();
            newprob.setVisible(true);
            ProdPanel.add(newprob);     
        }       
    }
    
    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    package consommateur;
    
    import static java.lang.Thread.sleep;
    
    /**
     *
     * @author Romain
     */
    public class Producteur {
        private int QtePdt; // Qte produite
        private int UT; // Unité de temps
        private int Max;
        
        public Producteur(){
            QtePdt = 5;
            UT = 100;        
        }
        
        public int getProducteurQtePdt(){
            return this.QtePdt;
        }
        
        public void setProducteurQtePdt(int Qte){
            this.QtePdt = Qte;
        }
        
        public void run(){
            for(int i = 1; i <= 0; i++){
                System.out.println(i);
                try{
                    sleep(UT);
                }
                catch(InterruptedException e){
                    System.out.println("Impossible de mettre en attente");
                }
                if(QtePdt == 0){
                    i = 0;
                }
            }        
        }
        
        
    }
    
    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    package consommateur;
    
    import java.awt.Color;
    import java.awt.event.ActionListener;
    import javax.swing.BoxLayout;
    import javax.swing.JButton;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SpringLayout;
    
    /**
     *
     * @author Romain
     */
    public class ProducteurView extends JPanel{   
        
        public ProducteurView(){
            JPanel ProducteurPanel = new JPanel();
            ProducteurPanel.setBackground(Color.yellow);
            ProducteurPanel.setLayout(new BoxLayout(ProducteurPanel, BoxLayout.PAGE_AXIS));
            JTextField ProducteurNumber = new JTextField();
            JTextField ProducteurQteProd = new JTextField();
            JTextField ProducteurUT = new JTextField();
            
            JButton ProducteurStop = new JButton();
            ProducteurStop.setText("STOP / WORK");
            ProducteurStop.setVisible(true);
            
            JButton ProducteurUpdate = new JButton();
            ProducteurUpdate.setText("Update");
            ProducteurUpdate.setVisible(true);
            
            
            //ProducteurNumber.setBounds(10,10,100,30);
            ProducteurNumber.setEditable(false);
            ProducteurNumber.setColumns(10);
            //ProducteurNumber.addActionListener(this);
            //add(ProducteurNumber);
            
            ProducteurQteProd.setBounds(10,10,100,30);
            //ProducteurQteProd.addActionListener(this);
            //add(ProducteurQteProd);
            
            ProducteurUT.setBounds(10,10,100,30);
            //ProducteurUT.addActionListener(this);
            //add(ProducteurUT);
                  
            
            ProducteurPanel.add(ProducteurNumber);
            ProducteurNumber.setVisible(true);
            ProducteurPanel.add(ProducteurQteProd);
            ProducteurQteProd.setVisible(true);
            ProducteurPanel.add(ProducteurUT);
            ProducteurQteProd.setVisible(true);
            ProducteurPanel.add(ProducteurStop);
            ProducteurPanel.add(ProducteurUpdate);
            
            ProducteurPanel.setVisible(true);
            add(ProducteurPanel);
            
            Producteur ProdThread = new Producteur();
            ProdThread.setProducteurQtePdt(1);
        }
    }

    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    package consommateur;
    
    import java.awt.Color;
    import java.awt.GridLayout;
    import java.awt.Insets;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.border.EmptyBorder;
    
    /**
     *
     * @author Romain
     */
    public class GrenierView extends JPanel {
       private int grenier = 0;
         
        public int getGrenier(){
            return grenier;
        }
         
        public void setGrenier(int stock){
            this.grenier = grenier + stock;
        }
        
        public GrenierView(){
        JPanel GrenierPanel = new JPanel();
        GrenierPanel.setLayout(new GridLayout(1,1));
        GrenierPanel.setBorder(new EmptyBorder(10,10,10,10));
        GrenierPanel.setBackground(Color.red);
        //GrenierPanel.setSize(100,100);
        JTextField GrenierTextField = new JTextField();    
        GrenierTextField.setColumns(50);
        GrenierTextField.setEnabled(true);
        GrenierPanel.add(GrenierTextField);
        GrenierTextField.setVisible(true);
        add(GrenierPanel);
        }
    }

    Voici le code tel que je l'exploite en vue de mettre en place mon thread.
    Je dois finaliser ce projet d'ici vendredi prochain, dc je fais un grand nombre d'essais infructueux.

    Merci à tous

    NB: je vise l'utilisation du modèle MVC ou plutot 3-tiers d'ici quelques mois, ne m'orientez pas trop vite dans ce sens, si je me perd avec ma facon de coder, n'hésité pas à me recadrer. Je sépare juste la partie graphique du code pour le moment.






    • Partager sur Facebook
    • Partager sur Twitter
      23 novembre 2014 à 23:31:26

      Salut,

      tu ne lances les thread à aucun moment. Tu pourrais faire hériter ta classe Producteur de Thread puis faire prodThread.start() ligne 66 dans ta classe ProducteurView. Je t'invite à lire le tutoriel sur les thread https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html (ou celui présent sur ce site).

      Quelques autres remarques :

      L'InterruptedException n'est pas levée lorsqu'un thread ne peut pas être mis en attente, mais lorsque la fonction interrupt est appelée sur ce thread. Regarde la documentation : https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#sleep-long-

      Pour ce qui est des conventions, on met un minuscule à la première lettre de chaque nom de variable (camel case). Exemple : GrenierPanel -> grenierPanel.

      Bonne soirée :)

      • Partager sur Facebook
      • Partager sur Twitter
        24 novembre 2014 à 12:05:14

        Bonjour,

        Merci de ta réponse, j'ai en effet négligé les conventions de noms. Je les corrigerais ce soir.

        Concernant les threads, tu me parles des thred synchronisé et des interruptions planifiée?
        Si c'est ca, je n'ai encore rien compris au fonctionnement. Juste l’intérêt de les utiliser de cette manière.
        Je mettrai ca en place d'ici demain si j'y arrive.

        Mais pour le moment, j'ai mis en pratique tes remarques sur le codes existants.

        public class Producteur extends Thread {
           
        ....
            
            @Override
            public void run(){
                for(int i = 1; i <= 0; i++){
                    System.out.println(i);
                    try{
                        sleep(UT);
                        System.out.println("T"+i);
                    }
                    catch(InterruptedException e){
                        System.out.println("Impossible de mettre en attente");
                    }
                    if(this.QtePdt == 0){
                        i = 0;
                    }
                }        
            }
            
            
        }
        

        J'ai donc adapté Producteur pour qu'il hérite de Thread. Ainsi que quelque éléments dont le @override dont l'utilisation n'est pas encore claire mais semble conseillé.

        Ensuite j'ai ajouté un start à la ProducteurView pour démarrer le thread, mais je n'ai rien qui apparait dans ma console.
        Si le thread démarre, je devrais voir des infos dans la console

        public class ProducteurView extends JPanel{   
            
        ...
                
                Producteur ProdThread = new Producteur();
                ProdThread.setProducteurQtePdt(1);
                ProdThread.start();
            }
        }

        Mon code s'exécute normalement pour la partie visuelle, mais au niveau code fonctionnel, je nage complètement.
        Si tu repasses sur le topic avant ce soir, peux tu me dire pourquoi le thread ne démarre pas, alors que sur un autre programme de test le start suffit à l'initialiser.

        Merci

        • Partager sur Facebook
        • Partager sur Twitter
          24 novembre 2014 à 15:57:26

          Reprenons ton code de la classe Producteur : 

                  for(int i = 1; i <= 0; i++){
                     ...
                  }       
          

          La boucle for s'exécute tant que i est inférieure ou égale à 0, or i vaut 1 telle que tu l'as initialisée. Donc la boucle ne s'exécutera jamais, et rien n'est affiché dans la console. 

          L'annotation @Override permet de dire au compilateur qu'on s'attend à redéfinir la méthode annotée. Si celle ci n'est pas présente dans l'interface ou la classe implémentée/héritée, alors le compilateur crée une erreur. Exemple : la classe A possède la méthode operation(int a, int b) qui additionne a et b. La classe B hérite de A et on veut redéfinir la méthode operation pour la soustraction. Si on écrit dans B : operation(float a, float b) et qu'on fait ensuite sur l'instance A obj = new B() un appel obj.operation(1,1) le résultat est 2 et non 0 ! Les deux méthodes operation n'ont pas la même signature. Le méthode operation est sur-définie et non redéfinie comme on le voulait. Pour être averti par le compilateur, il faut l'informer de notre intention de redéfinir cette méthode dans B avec l'annotation @Override

          Plutôt que "Impossible de mettre en attente" il est plus juste d'écrire quelque chose du genre "Demande d'interruption du thread".

          -
          Edité par tvere 24 novembre 2014 à 16:10:01

          • Partager sur Facebook
          • Partager sur Twitter
            24 novembre 2014 à 17:01:37

            A je n'avais vraiment pas vu, je me focalisait sur le démarrage du thread.

            Pour l'override c'est beaucoup plus claire maintenant, j'ai fais un peu de lecture.

            Je continue sur ma lancée, et je me demande pourquoi lorsque je fais un ProdThread.setProducteurQtePdt(1); cela ne fonctionne pas.
            Je suis censé pouvoir changer le temps du sleep mais ça marche pas.

            Si par contre je modifie la variable dans la classe Producteur UT = 1000 cela fonctionne.

            J'essaye de mettre en pause mon thread via un bouton dans le ProducteurView, mais pour le moment mon programme crash.
            Je posterai le code mis à jours lorsque cela fonctionnera.

            NB: je ne peux pas créer plusieurs instance de ma la classe ProducteurView avec un bouton dans le MainView, il me dit souligne en rouge ma ligne de code, serait-ce un problème de visibilité ? Ou dois-je créer un tableau de classe ProducteurView et ajouter mes classes à ce tableau à chaque fois que j'ai besoin d'une nouvelle vue (et thread).

            Je dois pouvoir ajouter et supprimer un producteur via l'interface graphique et donc couper son thread.

            Merci des infos ca m'aide vraiment, je commence à faire les consommateurs qui font l'exacte opposé du producteur.

            • Partager sur Facebook
            • Partager sur Twitter
              26 novembre 2014 à 13:02:39

              Lorsque tu appelles la fonction setProducteurQtePdt() tu ne modifies pas la valeur du champ UT, mais celle du champ QtePdt.

                  public void setProducteurQtePdt(int Qte){
                      this.QtePdt = Qte;
                  }
              


              Ajoute un this.UT = Qte si tu veux changer la valeur de UT et donc le temps de sleep en fonction du paramètre Qte. 

              Il n'existe aucun mécanisme prédéfini pour mettre en pause ou arrêter un thread. Je t'invite à lire le tutoriel sur la fermeture des threads sur ce site : http://openclassrooms.com/courses/bien-fermer-ses-threads-en-java.

               Si ton programme crash, copie l'erreur et poste la ici.

              • Partager sur Facebook
              • Partager sur Twitter
                30 novembre 2014 à 17:21:46

                Bonjour,

                Merci de toutes tes interventions. J'ai bien appris et mon application fonctionne presque comme elle devrait.
                Il me reste deux problèmes à résoudre, mais je vais créer un autre sujet, cela ne concerne plus les threads.

                Merci

                Update nouveau sujet avant 18h00

                • Partager sur Facebook
                • Partager sur Twitter

                Problème thread et communication entre classe

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown