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 :

Interruption et reprise d'un Thread


Sujet :

Concurrence et multi-thread Java

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    340
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 340
    Points : 139
    Points
    139
    Par défaut Interruption et reprise d'un Thread
    Voila, j'ai créé une classe qui lance, suspend et reprend un thread, via différentes méthodes.
    Voici cette classe:
    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
     
    package evolution;
     
    public class Vivre implements Runnable{
     
    	protected Thread t;
    	protected boolean encours,demarre;
    	protected Interface IHM=null;
     
    	public Vivre(Interface i){
    		encours=false;
    		demarre=false;
    		t=new Thread(this);
    		IHM=i;
     
    	}
     
    	public void Demarrer(){
    		t.start();
    		encours=true;
    	}
     
    	public void Reprendre(){
    		t.notify();
    		encours=true;
    	}
     
    	public void Suspendre() throws InterruptedException{
    		t.wait();
    		encours=false;
    	}
     
    	public synchronized void run() {
    		if(!demarre){
    			demarre=true;
    			while(IHM.grille.nbAmibe!=1){
    				try {
    					Interface.sortie.append(IHM.grille.vivre());
    					Thread.sleep(1500);
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				IHM.affichageInfo();
     
    			}
    		}
    	}
     
    }
    Je manipule un objet Vivre dans le action performed de mon IHM :
    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 Interface extends ... implements ...{
    protected Vivre v;
    public Interface(){
    v=new Vivre(this);
    [...]
    }
     
    public void actionPerformed(ActionEvent e) {
    			Object o = e.getSource();
    			/*
    			 * Action sur le bouton pour faire vivre la population
    			 */
    			if(o==boutonVie){
    				if(!v.encours){
    					if(!v.demarre) v.Demarrer();
    					else {
    						v.Reprendre();
    					}
    				} 
    				else
    				try {
    					v.Suspendre();
    				} catch (InterruptedException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
     
    			}
    [...]
    }
    }
    En l'état, lorsque je clique sur mon bouton Vivre, cela me lance bien le thread, et l'affichage de la grille avec des pauses de 1500ms.
    Mais il y a 2 problèmes :
    - lorsque j'utilisais la méthode de vie de la population, je passais directement de l'affichage de l'ancienne grille à la nouvelle grille. Or maintenant, l'affichage se fait "en direct", c'est à dire que je vois s'afficher chaque une par une, sachant que plus il y a de cases, et plus les dimensions de chacunes se réduisent, bref, c'est moche, et surtout je ne comprend pas pourquoi. Comment l'éviter???
    - le vrai problème, c'est qu'un nouveau clic sur le bouton vie ne produit rien, si ce n'est qu'une exception est levée :
    Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException: current thread not owner
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at evolution.Vivre.Suspendre(Vivre.java:28)
    at evolution.Interface.actionPerformed(Interface.java:1302)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)
    Pourquoi???

  2. #2
    Membre expérimenté
    Avatar de zekey
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 036
    Points : 1 403
    Points
    1 403
    Par défaut
    Sans chercher trop a comprendre ton code je vois un problème majeur: wait doit se trouver dans un bloc synchronized comme décris dans la doc http://java.sun.com/j2se/1.5.0/docs/...ct.html#wait()

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    340
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 340
    Points : 139
    Points
    139
    Par défaut
    bon, j'ai lu l'API de la classe Object, j'ai modifié mon code en conséquence :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public void Suspendre() {
    		Object o=new Object();
    		synchronized (o) {
    	         while (encours=false)
    				try {
    					o.wait();
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    	     }
    	}
    J'ai même essayer de mettre "this" comme verrou, mais rien ne change : j'ai toujours une exception " java.lang.IllegalMonitorStateException: current thread not owner " qui sort à l'appel de ma méthode reprendre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public void Reprendre(){
    		t.notify();
    		encours=true;
    	}

  4. #4
    Membre émérite
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Points : 2 582
    Points
    2 582

  5. #5
    Membre actif Avatar de jibbi
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 165
    Points : 205
    Points
    205
    Par défaut
    t'a essayé de placer ton synchronized dans le nom de la méthode au lieu dans un bloc;

    public synchronized void Suspendre() {}

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Points : 675
    Points
    675
    Par défaut
    Tel que, ca ne peut pas marcher.

    L'objet de synchronisation que tu as choisi est le thread. Tu as déclaré la methode run() synchronized, le monitor est pris, et ne sera relaché que lorsque tu sortiras de la methode run() (ou si dans la methode run(), tu avais ajouté un appel à wait, mais ce n'est pas le cas ici).
    Donc meme si tu englobes tes appels a t.notify() ou t.wait() dans un bloc synchronized, tu ne pourras pas prendre le monitor, puisque la methode run() l'a pris.

    En fait, je pense plutot qu'il y a probleme de conception.

    La premiere chose, c'est d'utiliser un objet de synchronisation qui ne soit pas le thread. Typiquement, ca peut être un attribut du genre
    Object lock = new Object();
    Il est techniquement possible d'utiliser thread comme objet de synchronisation, mais je trouve ca beaucoup moins clair.

    Ensuite, il faut gerer la suspension et la reprise dans la methode run() de ton thread. Typiquement, il faut quelque chose du genre

    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
    public void run() {
          while (true) {
                 synchronized (lock) {
                      if (!en_attente) 
                         lock.wait(1500);
                     if (stop_thread)
                         break;
                     if (en_attente)
                        lock.wait();
                     if (stop_thread)
                         break;
                 }
                 ...
                 mon_code();
                 ...
          }
    }
    Et pour les methodes pour suspendre et reprendre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public void suspendre() {
       synchronized(lock) {
           en_attente = true;       
       }
    }
     
     
    public void rependre() {
       synchronized(lock) {
           en_attente = false;       
           lock.notify();
       }
    }

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    340
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 340
    Points : 139
    Points
    139
    Par défaut
    ok, voila qui m'éclaircit sur la synchronisation. Mais j'ai qq questions :
    - dans le run, tu mets while(true), mais sur quoi est effectué le test ? doù vient ce true et qd est il modifié?
    - qu'est ce que ce stop thread?
    - pourquoi mettre du code "mon_code" hors du synchronized?

    edit : l'object lock, je le déclare comme champ de classe et le construit dans le constructeur ou alors je le déclare en local ?

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    340
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 340
    Points : 139
    Points
    139
    Par défaut
    C'est bon, maintenant, ça marche.
    Voici le code. Si j'ai codé de façon maladroite, dites le moi.
    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
     
    public void run() {
    		while (IHM.grille.nbAmibe!=1) { 
    			synchronized (lock) {  
    				if (en_cours) {
    					try {
    						Interface.sortie.append(IHM.grille.vivre());
    						IHM.affichageInfo();
    						lock.wait(1500);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					} 
    				}
     
    				if (!en_cours) { 
    					try {
    						lock.wait();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					} 
    				}
    			}  
    		}	
    	}
    Edit : j'ai toujours le problème d'affichage "QUI RAME" quand je le commande par thread. Quand je ne passais pas par un thread pour raffraichir mon affiichage, celui était immédiat. Maintenant, avec le thread, pour une largeur de 6, l'affichage dure environ 1 secondes, et pour une largeur de 12, il dure logiquement 4 fois plus (vu qu'il y a 4 fois plus de cases), donc 4 secondes. Non seulement, c'est très long, mais en plus, on voit apparaître toutes les cases une par une, ce qui est Moche et rend difficile la visualisation des changements par rapport au précédent affichage...
    Que faire pour dynamiser cet affichage? Pourquoi l'utilisation d'un thread ralentit-elle l'affichage?

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Points : 675
    Points
    675
    Par défaut
    Citation Envoyé par michaeljeru
    ok, voila qui m'éclaircit sur la synchronisation. Mais j'ai qq questions :
    - dans le run, tu mets while(true), mais sur quoi est effectué le test ? doù vient ce true et qd est il modifié?
    - qu'est ce que ce stop thread?
    J'ai mis while (true), parce que je veux que la condition de sortie (ici stop_thread) soit dans un block synchronized. En d'autre termes, je veux être sur qu'au moment ou je lis la condition de sortie, personne ne la modifie.
    J'ai mis ici un attribut stop_thread, pour l'exemple, mais dans ton cas, ta condition a l'air d'etre

    Citation Envoyé par michaeljeru
    - pourquoi mettre du code "mon_code" hors du synchronized?
    Parce je n'avais pas de raison de la mettre dans le bloc synchronized. La synchronisation permet ici de gerer seulement la suspension et la reprise du traitement.
    Mettre mon_code de le bloc synchronized, ca veut dire que le thread qui va demander la suspension du thread va être bloqué jusqu'à la fin du traitement.
    Mettre mon_code au dehors du bloc, ca veut dire que le thread appelant fera la demande sans être bloqué.
    A toi de voir dans ton cas ce qui convient le mieux.

    Citation Envoyé par michaeljeru
    edit : l'object lock, je le déclare comme champ de classe et le construit dans le constructeur ou alors je le déclare en local ?
    Il faut le declarer comme un attribut, et le créer dans le constructeur.

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Points : 675
    Points
    675
    Par défaut
    Citation Envoyé par michaeljeru
    Voici le code. Si j'ai codé de façon maladroite, dites le moi.
    Ok, alors voici quelques petites remarques :
    - appeler une classe Interface, c'est vraiment par terrible.
    - l'acces direct aux membres static d'une classe est à eviter.
    - renseigne toi également sur le design pattern singleton, et essaie de l'appliquer à ta classe IHM
    - ta condition de sortie de la boucle while va être modifiée par un autre thread, il vaudrait mieux en protéger l'acces
    - est ce normal d'attendre 1500 ms, à chaque boucle, si en_cours est vrai ?

    Citation Envoyé par michaeljeru
    Que faire pour dynamiser cet affichage? Pourquoi l'utilisation d'un thread ralentit-elle l'affichage?
    D'une manière général, l'utilisation d'un thread ne ralentit pas (ou si peu) l'execution d'un programme. Les temps de commutation d'un thread à l'autre sont négligeables par rapport au temps d'execution globale.
    Dans ton cas, je pense qu'il s'agit simplement d'une mauvaise utilisation, d'un bug, que tu vas bientot trouver (courage).

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Points : 675
    Points
    675
    Par défaut
    Regarde egalement du coté de la classe javax.swing.Timer, qui doit remplacer avantageusement ton thread

  12. #12
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    340
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 340
    Points : 139
    Points
    139
    Par défaut
    Géniale ton idée !!! Merci. Ca marche comme ça, c'est beaucoup plus simple qu'avec la synchronisation des threads, et je n'ai plus cet effet ralenti...
    Par contre, petite bizarrerie, quand je fixe un delay, mettons 1 seconde, le premier affichage ne se fait qu'après... 2 secondes. Alors pour de petits délais, ça ne se voit presque pas, mais quand je mets 2,5s, là, on se demande pourquoi il ne se passe rien...
    Merci beaucoup à tous.

Discussions similaires

  1. interruption et reprise d'un thread
    Par Virgile le chat dans le forum Concurrence et multi-thread
    Réponses: 4
    Dernier message: 09/07/2007, 13h28
  2. arret et reprise d'un thread
    Par voyageur dans le forum Windows Forms
    Réponses: 13
    Dernier message: 09/04/2007, 10h39
  3. Interruption et reprise d'un Thread
    Par Nuro dans le forum Concurrence et multi-thread
    Réponses: 1
    Dernier message: 28/02/2007, 21h34
  4. pause et reprise de thread
    Par raggadoll dans le forum C++Builder
    Réponses: 5
    Dernier message: 12/07/2003, 10h50
  5. Pause et reprise d'un thread
    Par raggadoll dans le forum Linux
    Réponses: 5
    Dernier message: 03/07/2003, 20h22

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