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

2D Java Discussion :

Modification et lecture d'une instance par 2 threads en même temps


Sujet :

2D Java

  1. #1
    Membre habitué Avatar de Pecose
    Homme Profil pro
    Batiment
    Inscrit en
    Février 2013
    Messages
    310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Batiment
    Secteur : Bâtiment

    Informations forums :
    Inscription : Février 2013
    Messages : 310
    Points : 194
    Points
    194
    Par défaut Modification et lecture d'une instance par 2 threads en même temps
    Bonjour a tous,
    Voila mon problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public class World {
    	public ArrayList<Rectangle> rectangle = new ArrayList<Rectangle>(); 
    	public World(){}
    	public void Creation(){ rectangle.add(new Rectangle()); }
    	public void Update(){ rectangle.get(0).setRect(Panel.getMX(), Panel.getMY(), 100, 100); }
    	public void Display(){ Panel.feuille.draw(rectangle.get(0)); }
    }
    Update est appeler depuis un thread contrairement a Display.
    Ce qui pose ce problème évident: Display essaye d'afficher rectangle.get(0) qui en même temps est modifier par Update.

    Comment je fait a ce que Display ne puisse accéder qu'aux variables qui ne sont pas en cour de traitement?
    Merci de votre aide.

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Pour empêche 2 threads d'accèder à la même instance au même moment, pour les cas simples, on utilise le mot clef synchronized. Ce mot clef impose qu'un seul thread puisse utiliser la référence synchronisée pendant la durée du bloc synchronisé (on peut mettre synchronized également sur une méthode : la référence synchronisée est alors celle de l'instance de classe qui a la méthode).

    Dans ton cas, il s'agit de la référence de Rectangle qu'il y a dans la liste, à la position 0.

    Il faudrait donc écrire :

    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 class World {
    	public ArrayList<Rectangle> rectangle = new ArrayList<Rectangle>(); 
    	public World(){}
    	public void Creation(){ rectangle.add(new Rectangle()); }
    	public void Update(){ update(rectangle.get(0))}
     
            private void update(Rectangle rectangle) {
                  synchronized( rectangle ) {
                       rectangle.setRect(Panel.getMX(), Panel.getMY(), 100, 100); 
                  }
             }
     
    	public void Display(){ display(rectangle.get(0) }
     
             private void display(Rectangle rectangle) {
                   synchronized(rectangle) {
                         Panel.feuille.draw(rectangle);
                   }
             }
     
    }
    Mais attention aux problèmes de deadlock : lorsqu'un thread 1 arrive sur le bloc synchronisé et qu'un autre thread 2 est déjà entré dedans, il va être mis en attente. Mais le thread 1 peut être déjà en train de bloquer une autre référence, qui est synchronisée ailleurs dans un bloc que le thread 2 pourrait exécuter avant de sortir du bloc qui bloque thread 1. Les 2 threads seraient interbloqués indéfiniment.

    Ici, on pourrait potentiellement avoir le cas, puisque je vois que update() accède à des propriétés de Panel, qui est la classe qui dessine. Attention, donc, si tu dois également gérer l'accès concurrent aux variables manipulées dans getMX() et getMY().

  3. #3
    Membre habitué Avatar de Pecose
    Homme Profil pro
    Batiment
    Inscrit en
    Février 2013
    Messages
    310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Batiment
    Secteur : Bâtiment

    Informations forums :
    Inscription : Février 2013
    Messages : 310
    Points : 194
    Points
    194
    Par défaut
    Alors merci mais après test ca ne règle pas le problème.
    Tu me demande de mettre synchronized sur Update et Display mais c'est sur ArrayList<Rectangle> rectangle qu'il faudrait que je le mette.
    Là ce qu'il ce passe c'est que Update, qui est appeler par un Thread, modifie la valeur de rectangle en même temps que Display la récupère pour l'afficher.
    Que je mette synchronized sur Display ou Update ca revient au même.
    Il faudrait peut être que je mette synchronized sur une méthode qui soit "set" et "get" en même temps... mais comment faire?

  4. #4
    Membre habitué Avatar de Pecose
    Homme Profil pro
    Batiment
    Inscrit en
    Février 2013
    Messages
    310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Batiment
    Secteur : Bâtiment

    Informations forums :
    Inscription : Février 2013
    Messages : 310
    Points : 194
    Points
    194
    Par défaut
    J'ai essayer ca:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public synchronized void Controle(boolean x){
    		if(x){Update();}
    		else{Display();}
    	}
    Je sais pas si ce que j'ai voulu faire et compréhensible mais en tout cas ca ne marche pas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Exception in thread "AWT-EventQueue-0" java.lang.IllegalThreadStateException

  5. #5
    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,



    Si on utilises la synchronisation, il faut impérativement synchroniser tous les accès à la variables, et via le même lock.

    Dans le code de joel.drigo c'est la variable de type Rectangle qui est synchronisé... mais pas l'accès à l'ArrayList<Rectangle> !
    Elle doit également l'être si des modif (via Creation()) peuvent intervenir en même temps.


    Ensuite il faut bien utiliser le même lock partout où les ressources partagées sont utilisées...
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    	/*
    	 * L'attribut doit être private, pour être sûr que personne n'y accède directement.
             * Il est préférable qu'il soit également final si on l'utilise comme lock.
    	 */
    	private final ArrayList<Rectangle> rectangle = new ArrayList<Rectangle>(); 
     
    	public World(){}
     
    	public synchronized void Creation(){ rectangle.add(new Rectangle()); }
    	public synchronized void Update(){ rectangle.get(0).setRect(Panel.getMX(), Panel.getMY(), 100, 100); }
    	public synchronized void Display(){ Panel.feuille.draw(rectangle.get(0)); }
    Mais faut faire gaffe aux dead-locks...



    Citation Envoyé par Pecose Voir le message
    Update est appeler depuis un thread contrairement a Display.
    Que veux-tu dire par là exactement ? Une méthode est forcément exécuté dans un thread...


    Sinon qu'est-ce que tu utilises pour l'affichage ?
    En général on utilise un système mono-thread pour tout ce qui touche à l'affichage (c'est plus simple et moins casse-gueule).


    a++

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Pecose Voir le message
    Alors merci mais après test ca ne règle pas le problème.
    Tu me demande de mettre synchronized sur Update et Display mais c'est sur ArrayList<Rectangle> rectangle qu'il faudrait que je le mette.
    Dans le code posté, tu modifies d'une part une instance de rectangle présent dans une ArrayList et d'autre part la même instance est utilisée pour être dessinée. Il n'y aucun conflit sur l'ArrayList dans ce traitement. Ce serait effectivement le cas si tu ajoutais un rectangle dans un thread, pendant que tu parcours la liste de rectangle de l'autre (et le problème serait même différent).

    Ici, le problème est que tu as un thread qui modifie les coordonnées d'un rectangle pendant qu'un autre le modifie : comme il n'est pas possible de tout modifier d'un coup sans que ça prenne un tout petit peu de temps, on va commencer à dessiner un rectangle qui n'est plus le même à la fin du dessin.

    D'ailleurs, tu n'aurais pas du tout le problème si tu faisais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public void Update(){ rectangle.set(0, new Rectangle(Panel.getMX(), Panel.getMY(), 100, 100);) }
    Dans ce cas, les deux rectangles seraient des instances différentes et donc pas de conflit. La modification de la case de tableau qui stocke la référence étant atomique, on ne peut lire et écrire de toute manière cette référence en même temps. Il y a forcément un des threads qui fait son action avant l'autre.

    Tu es sûr que le problème ne vient pas de getMX() et getMY() plutôt ?

    Par contre, dans ce code, tu ne synchronise pas l'instance de Rectangle, mais l'instance de la classe qui contient la méthode controle().

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public synchronized void Controle(boolean x){
    		if(x){Update();}
    		else{Display();}
    	}

  7. #7
    Membre habitué Avatar de Pecose
    Homme Profil pro
    Batiment
    Inscrit en
    Février 2013
    Messages
    310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Batiment
    Secteur : Bâtiment

    Informations forums :
    Inscription : Février 2013
    Messages : 310
    Points : 194
    Points
    194
    Par défaut
    Tu es sûr que le problème ne vient pas de getMX() et getMY() plutôt ?
    Sur! J'ai remplacer par 10,10. Même résulta.
    Par contre, dans ce code, tu ne synchronise pas l'instance de Rectangle, mais l'instance de la classe qui contient la méthode controle().
    Oui je sais, j'était parti sur autre chose, je sais pas si c'est possible de synchronise l'instance de Rectangle.

    Par contre, l'erreur que j'ai envoyer me dit que le souci viens de là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Pattern {
    	private static World world = new World();
    	private final InternalProcess internalProcess = new InternalProcess();
    	public Pattern(){}
    	public static World getWorld(){ return world; }
    	public void Statement(){ world.Creation(); }
    	public void Update(){ internalProcess.start();}//ici
    	public void Display(){ world.Controle(false); }
    }
    ca va là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class InternalProcess extends Thread{
    	public InternalProcess(){};
    	public void run(){ Pattern.getWorld().Controle(true); }
    }

  8. #8
    Membre habitué Avatar de Pecose
    Homme Profil pro
    Batiment
    Inscrit en
    Février 2013
    Messages
    310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Batiment
    Secteur : Bâtiment

    Informations forums :
    Inscription : Février 2013
    Messages : 310
    Points : 194
    Points
    194
    Par défaut
    C'est bon j'ai trouver:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public void Update(){ internalProcess = new InternalProcess(); internalProcess.start();}
    Je crois que c'est tout, merci de votre aide.

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 03/04/2008, 16h05
  2. créer une instance par introspection
    Par PoichOU dans le forum Langage
    Réponses: 2
    Dernier message: 10/01/2008, 13h10
  3. Réponses: 5
    Dernier message: 17/07/2006, 18h34
  4. [MySQL] Modification des données d'une base par les membres
    Par pod1978 dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 22/03/2006, 17h25
  5. [VB.NET]Créer une instance par page
    Par Dnx dans le forum ASP.NET
    Réponses: 20
    Dernier message: 31/10/2005, 13h22

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