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 :

Synchronisation entre Threads


Sujet :

Concurrence et multi-thread Java

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2012
    Messages : 66
    Points : 49
    Points
    49
    Par défaut Synchronisation entre Threads
    Bonsoir,

    Je fais une simulation de course. Les coureurs sont représentés avec des JPROGRESSBAR et la vitesse d'un coureur dépend du temps d'endormissement au hasard (entre 0.5 et 3 seconde). Tout marche bien ou presque.
    En fait, j'ai fait l'appli en MVC. Quand un coureur arrive, le Manager lui attribut une position.
    Dans le Manager il y a un attribut static "POSITIONFINALE" qui s'incrémente de 1 à chaque fois qu'un coureur est arrivé.
    La méthode qui attribut la position et le temps couru est synchronisée, sinon 2 coureurs qui arrivent en même temps auraient une position identique.

    Mon problème :
    Que je mette "synchronized" ou pas je ne vois pas de différence

    Manager.java :

    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
    public class Manager {
     
    	private static Manager INSTANCE = null;
    	private ArrayList<Coureur> lesCoureurs = new ArrayList<Coureur>();
    	private Course laVue;
    	private static int POSITIONFINALE = 1;
     
    	private Manager(){
    		Coureur lievre = new Coureur("Lievre");
    		Coureur tortue = new Coureur("Tortue");
    		Coureur girafe = new Coureur("Girafe");
    		Coureur lion = new Coureur("Lion");
    		Coureur gazelle = new Coureur("Gazelle");
     
    		lesCoureurs.add(lievre);
    		lesCoureurs.add(tortue);
    		lesCoureurs.add(girafe);
    		lesCoureurs.add(lion);
    		lesCoureurs.add(gazelle);
     
    	}
     
    	public static Manager GETINSTANCE() {
    		INSTANCE = new Manager();
    		return INSTANCE;
    	}
     
    	public void setVue(Course v){
    		this.laVue = v;
    	}
     
    	public ArrayList<Coureur> getLesCoureurs() {
    		return this.lesCoureurs;
    	}
     
    	public void mettreNom() {
    		for (BarreProgression barreCoureur : laVue.COUREURSGUI) {
    			barreCoureur.setTitre(lesCoureurs.get(laVue.COUREURSGUI.indexOf(barreCoureur)).getNom());
    		}
    	}
     
    	public void mettreListeners() {
    		for (BarreProgression barreCoureur : laVue.COUREURSGUI) {
    			lesCoureurs.get(laVue.COUREURSGUI.indexOf(barreCoureur)).addCoureurListener(barreCoureur);
    		}
    	}
     
    	public synchronized void mettrePositionFinale(Coureur c) {
    		c.setTemps();
    		c.setPositionFinale(POSITIONFINALE);
    		POSITIONFINALE++;
    	}
     
    	public void demarre(){
    		mettreListeners();
    		Iterator<Coureur> itCoureur = lesCoureurs.iterator();
     
    		while (itCoureur.hasNext()) {
    			Thread coureur = new Thread(itCoureur.next());
    			coureur.start();
    		}
    	}
     
    }
    Coureur.java :

    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
    public class Coureur implements Runnable{
    	private final EventListenerList listeners = new EventListenerList();
    	private Animal unAnimal;
    	private long temps;
     
    	public Coureur(String nom){
    		this.unAnimal = new Animal(nom);
    	}
     
    	public void run(){
    		temps = (long) ((System.currentTimeMillis()/1000.0)%60);
    		while (getPosition() <= Course.ARRIVE) {
    			avancer();
    			fireAvancement();
    			if(getPosition() == Course.ARRIVE){
    				Manager.GETINSTANCE().mettrePositionFinale(this);
    				fireFinCoureur();				
    			}
    			pause(endormissement());		
    		}
    	}
     
    	public long getTemps() {
    		return temps;
    	}
     
    	public void setTemps() {
    		temps = (long) (((System.currentTimeMillis()/1000.0)%60) - temps);
    	}
     
    	public int getPositionFinale() {
    		return unAnimal.getPositionFinale();
    	}
     
    	public void setPositionFinale(int position){
    		unAnimal.setPositionFinale(position);
    	}
     
    	public String getNom(){
    		return this.unAnimal.getNom();
    	}
     
    	public int getPosition() {
    		return this.unAnimal.getPosition();
    	}
     
    	public void avancer() {
    		this.unAnimal.avancer();
    	}
     
    	public void addCoureurListener(CoureurListener listener){
    		listeners.add(CoureurListener.class, listener);
    	}
     
    	public void removeCoureurListener(CoureurListener listener){
    		listeners.remove(CoureurListener.class, listener);
    	}
     
    	public CoureurListener[] getCoureurListeners(){
    		return listeners.getListeners(CoureurListener.class);
    	}
     
    	protected void fireAvancement(){
    		for (CoureurListener listener : getCoureurListeners()) {
    			listener.avancementCoureur(getPosition());
    		}
    	}
     
    	protected void fireFinCoureur(){
    		for (CoureurListener listener : getCoureurListeners()) {
    			listener.finCoureur(getTemps(), getPositionFinale());
    		}
    	}
     
    	// de 0.5 à 3 secondes
    	private int endormissement(){
    		Random rand = new Random();
    		int tempsEndormit = rand.nextInt(3000 - 0 + 1) + 0;
     
    		return tempsEndormit;
    	}
     
    	private void pause(int temps){
    		try{
    			Thread.sleep(temps);					
    		}catch(InterruptedException e){
    			e.printStackTrace();
    		}
    	}
    }
    Merci d'avance de votre aide

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Quelle différence tu voudrais voir?

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2012
    Messages : 66
    Points : 49
    Points
    49
    Par défaut
    Par exemple, sans le "synchronized", 2 coureurs qui arrivent en même temps, accèderaient simultanément à la méthode, et auraient la même position

  4. #4
    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 : 54
    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,

    synchronized agit sur les instances : or, dans ton progamme, chaque thread accède à une instance différente de Manager. Le synchronized ne permet donc pas l'exclusion mutuelle de chaque thread.

    Cela vient de là :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public static Manager GETINSTANCE() {
    		INSTANCE = new Manager();
    		return INSTANCE;
    }
    Tu as voulu faire un singleton lazy, mais pas correctement, donc ça n'est pas un singleton (à chaque appel, son instance).

    soit tu fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public static synchronized Manager GETINSTANCE() {
                    if ( INSTANCE==null ) {
    		    INSTANCE = new Manager();
                    }
    		return INSTANCE;
    }
    Mais à la limite pourquoi s'embêter avec un singleton lazy ? Fais carrément un singleton préinitialisé, ou même passe ton manager au coureur, vu qu'il est de toute manière dépendant du singleton, et que tu instancies les coureurs dans le constructeur de celui-ci.

    D'ailleurs, tu peux passer POSITIONINITIALE en non static, utiliser un AtomicInteger (voir même un volatile int que tu incrémentes par ++i, l'opération étant atomique) pour éviter d'avoir à synchroniser, et ça devrait être bon.

    Avec AtomicInteger :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    private AtomicInteger positionInitiale = new AtomicInteger(1);
     
    public void mettrePositionFinale(Coureur c) {
    		c.setTemps();
    		c.setPositionFinale(positionInitial.getAndIncrement());
    }
    avec volatile int :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    private volatile int positionInitiale = 1;
     
    public void mettrePositionFinale(Coureur c) {
    		c.setTemps();
    		c.setPositionFinale(++positionInitial);
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2012
    Messages : 66
    Points : 49
    Points
    49
    Par défaut
    Merci c'est plus clair.

    En fait, la synchro est demandée dans le TP c'est pour cela.

    Dernière question, si je synchronise l'instanciation du Manager comme tu m'a dit, est-ce que ça en vaut la peine de synchroniser la méthode "mettrePositionFinale(Coureur c)" ?

  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 : 54
    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 hotman1313 Voir le message
    Merci c'est plus clair.

    En fait, la synchro est demandée dans le TP c'est pour cela.

    Dernière question, si je synchronise l'instanciation du Manager comme tu m'a dit, est-ce que ça en vaut la peine de synchroniser la méthode "mettrePositionFinale(Coureur c)" ?
    Oui, il faut aussi synchronizer la méthode mettrePositionFinale : synchronizer une méthode signifier synchronizer sur l'instance lors de l'appel de la méthode, ce qui garantit que plusieurs threads ne peuvent exécuter le code de la méthode en même temps, ce que tu cherches à faire.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  7. #7
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2012
    Messages : 66
    Points : 49
    Points
    49
    Par défaut
    Merci beaucoup. Je passe le sujet en résolu

  8. #8
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par hotman1313 Voir le message
    Par exemple, sans le "synchronized", 2 coureurs qui arrivent en même temps, accèderaient simultanément à la méthode, et auraient la même position
    Oui, sauf que ce n'est pas parce que tu retire le synchronized que du coup, le coureur vont sytématiquement arriver en même temps dans la méthode. C'est très difficile d'avoir deux threads en même temps dans une méthode aussi courte que la tienne donc le temps d'exécution doit se calculer en micro secondes. Le synchronized est là pour éviter les ennuis le jour où ça sera le cas, mais ca arrivera peut être une fois tous millions d'appels. Le moyenne le plus efficace pour voir une différence, c'est de mettre une sleep dans la méthode, ou de suspendre en debug entre le calcul de la nouvelle valeur et son stockage, histoire que plusieurs threads puissent faire ce calcul exactement en même temps.

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

Discussions similaires

  1. Synchronisation entre Thread
    Par Red Sno dans le forum Débuter
    Réponses: 2
    Dernier message: 12/12/2012, 21h38
  2. Problème de synchronisation entre Thread et VCL
    Par Jipété dans le forum Débuter
    Réponses: 33
    Dernier message: 21/05/2012, 11h14
  3. Problème de rafraichissement [EDIT: Synchronisation entre threads ]
    Par Nicolus dans le forum GTK+ avec C & C++
    Réponses: 4
    Dernier message: 29/10/2011, 14h37
  4. Réponses: 2
    Dernier message: 29/04/2007, 19h59
  5. Synchronisation entre 2 threads
    Par bodbod dans le forum C++
    Réponses: 8
    Dernier message: 20/08/2004, 18h29

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