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 :

Problème synchronisation threads


Sujet :

Concurrence et multi-thread Java

  1. #1
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut Problème synchronisation threads
    Moi j'ai une question synchro...
    Comment je peux faire lancer une méthode synchronized en Java par un thread alors qu'un autre thread est déjà en train de l'exécuter?
    (Sachant que je ne peux pas la désynchroniser vu qu'il y a une méthode wait() (d'où le blocage du premier thread dedans) et notifyAll() (pour débloquer le fameux thread)

    Je sais justement que ce n'est normalement pas possible mais dans mon application j'aimerais (en fait cette méthode est synchronized plus pour pouvoir faire appel aux méthodes notifyAll() et wait() que pour empecher une exécution de code critique.
    Linio

  2. #2
    Membre averti
    Homme Profil pro
    Développeur Java
    Inscrit en
    Avril 2004
    Messages
    265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Avril 2004
    Messages : 265
    Points : 342
    Points
    342
    Par défaut
    Comprend pas bien... Tu devrais mettre un peu de code, pour etayer ta question...

    A premiere vue, ma réponse serait, on ne peut pas, si ta méthodes est synchronisée, il n'y aura jamais deux threads qui l'éxécuteront en même temps (c'est le principe)...

  3. #3
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    Voilà la fameuse méthode.
    Produit étant un simple vector<produit>
    Voilà justement je sais que cette méthode est synchro donc normalement non exécutable par plusieurs threads, mais moi je veux pouvoir la faire exécuter par plusieurs threads tout en gardant les wait et notify...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public synchronized void reception(Produit p){
            while (produits.contains(p)){
                System.out.println("bloqué dans"+nom);
                try{
                    wait();
                } catch (Exception e) {
                    System.out.println("Erreur dans reception "+e);
                }
            }
            produits.add(p);
            System.out.println("Produit ajouté dans "+nom);
            notifyAll();
        }
    Linio

  4. #4
    Membre averti Avatar de soad
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    520
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Février 2004
    Messages : 520
    Points : 439
    Points
    439
    Par défaut Re: Problème synchronisation threads
    Citation Envoyé par Linio
    Comment je peux faire lancer une méthode synchronized en Java par un thread alors qu'un autre thread est déjà en train de l'exécuter?
    tu enlève le synchronized de ta fonction...

    ou alors comme ca:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public void maFonction() {
     
        synchronized(this) {
     
            // partie du code à synchronisé...
        }
     
        // suite du code...
        wait();
    }

  5. #5
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    J'ai essayé les blocs, synchronized(this).
    Mais bon voilà ça verrouille exactement de la même manière les parties que je ne voudrais pas voir verrouillées (à savoir le notifyAll())

    Si je synchronise avec un autre objet de la classe, ça part en sucette comme qui dirait avec des : Current Thread is not owner (erreur comme si la méthode était pas synchro)

    P.S: ta portion de code pourrait faire planter mon appli, les wait devant être dans des blocs synchro, sinon ça donne:

    Erreur dans reception java.lang.IllegalMonitorStateException: current thread not owner
    Linio

  6. #6
    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 je comprend bien tu souhaites que ton thread attende que le produit soit bien ajouté pour continuer...

    Si tu utilises Java 5.0 tu peux utiliser la nouvelle API de concurrence pour cela, tu as un exemple ici :
    http://www.developpez.net/forums/vie...386079#2386079

    a++

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 151
    Points : 144
    Points
    144
    Par défaut
    Salut linio ( c'est juju de mirage).

    En fait ce que je ne comprends pas puisque la méthode add de vector est synchronized et garantit l'exclusion mutuelle. pourquoi ne pas faire tout simplement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public void reception(Objcet o){
    //traitement à faire avant ajout
    vect.add(o);
    //traitement à faire apres ajout.
    }
    L'interet ( et inconvénient pour les perfos) des vector sur les arraylist étant que les méthodes de modification sont synchronizées. Je ne vois pas trop l'interet d'essayer de synchronizer un truc qui l'est déjà. En plus mettre des synchronized n'est pas sans effet pour le déroulement de l'appli donc je pense qu'il faut en mettre le moins possible ( c'est à dire uniquement quand il en faut) et éviter au maximum defaire des gros blocs synchronized.

    Si j'ai bien compris le problème, tu te compliques trop.

  8. #8
    Membre averti Avatar de soad
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    520
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Février 2004
    Messages : 520
    Points : 439
    Points
    439
    Par défaut
    Citation Envoyé par Linio
    J'ai essayé les blocs, synchronized(this).
    Mais bon voilà ça verrouille exactement de la même manière les parties que je ne voudrais pas voir verrouillées (à savoir le notifyAll())

    Si je synchronise avec un autre objet de la classe, ça part en sucette comme qui dirait avec des : Current Thread is not owner (erreur comme si la méthode était pas synchro)

    P.S: ta portion de code pourrait faire planter mon appli, les wait devant être dans des blocs synchro, sinon ça donne:

    Erreur dans reception java.lang.IllegalMonitorStateException: current thread not owner
    Oui, synchronized() synchronise l'objet passé en paramarètre donc this est l'objet courant dans le kel tu te trouve... tu peux tres bien mettre autre chose que this ...

  9. #9
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    En fait kisame je ne peux pas faire ça.
    Sinon les méthodes notifyAll() plantent.
    De fait j'ai un problème de moniteurs semblent-il je ne dois pas appeler la méthode wait dans la classe dans laquelle je l'appelle (le producteur appelle la méthode wait() de machin ce qui lui fait attendre dans le moniteur de la machine alors qu'il devrait attendre et être notifié dans son propre moniteur)

    Donc il faut que je recode ça.
    Merci en tout cas vos renseignements m'ont amené vers la bonne route.
    Je ne sais pas comment on met "résolu" donc si quelqu'un peut me dire.

    Merci.
    Linio

  10. #10
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    J'ai un autre souci (désolé de vous déranger mais là je ne vois vraiment pas du tout d'où ça peut venir, et ça fait plusieurs heures que je bosse dessus)

    Mon programme est donc un programme multithreadé qui gère une pseudo usine. Chaque bloc est relié à d'autres blocs, soit des emetteurs dont il recoivent des produits soit des récepteurs à qui ils envoient des produits.

    Mon programme tourne et puis finit à un moment donné par s'arrêter, le nombre d'itération varie à chaque lancement mais il semble toujours se bloquer au même endroit:
    Code de l'appelant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public synchronized void envoi() {
        	produitconsommes++;
            produits.clear();
            System.out.println("C2");
            emetteurs.get(0).reveil();
            System.out.println("C3");
        }
    Code de la méthode appelée dans emetteurs.get(0):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public void reveil(){
        	System.out.println("Reveil de la machine");
        	synchronized(this){
        		System.out.println("C4");
        		notifyAll();
        	}
        	System.out.println("C5");
        }
    L'affichage produit:


    ...
    Affichage précédent
    ...
    C2 :Thread[Thread-5,5,main]
    Reveil de la machine


    Et là plus rien le programme est bloqué, ainsi que l'affichage graphique, plus rien ne tourne (ce qui est normal si un thread bloque tous les autres par chainage finissent pareil)

    Sachant que la méthode reveil() n'est appelée que par cet objet (donc pas de blocage sur le synchronized, et même le notifyAll() s'exécute instantannément normalement? Il y a d'autres méthodes synchronized dans les deux classes mais je ne vois pas pourquoi ça viendrait de là puisque chaque bloc a son verrou...?

    Enfin je piétine complètement...
    Linio

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 151
    Points : 144
    Points
    144
    Par défaut
    ben tu as un deadlock
    Je ne sais pas exactement comment fonctionne une méthode synchronized mais à mon avis ça fait un synchronized sur this dans la méthode et puis apres tu refais un synchronized sur this dans ta méthode réveil.

    Je suis pas certain de ce que je dis.

    Essaye de synchronizer sur un autre objet que this pour voir ce que ça donne dans la méthode réveil.

  12. #12
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    J'ai déjà essayé, mais il me fait:

    Exception in thread "Thread-6" java.lang.IllegalMonitorStateException: current thread not owner
    at java.lang.Object.notifyAll(Native Method)
    at be.Machine.reveil(Machine.java:51)
    at be.Consommateur.envoi(Consommateur.java:37)
    at be.Consommateur.run(Consommateur.java:87)
    Linio

  13. #13
    Membre régulier

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 84
    Points : 75
    Points
    75
    Par défaut
    Kisame à raison, si ce code bloque ton programme, c'est que dans ton code, il y a un autre moniteur sur this (l'instance de l'objet courant). Regarde bien dans le code de ta classe, il faut savoir aussi que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    synchronized void toto(){
    }
    est équivalent à

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void toto(){
    synchronised(this){
    }
    }
    Tu peut donc avoir synchroniser une autre méthode qui en fait bloque ta méthode.

  14. #14
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    Mais alors ça veut dire qu'une autre méthode était en mode wait bloque toutes les threads voulant accéder à des méthodes synchronisées sur cet objet??

    Je vois pas bien comment la synchro fonctionne alors puisque qu'un bloc avec une ligne wait pourrait jamais être réveillé par un bloc avec une ligne notifyAll()

    Rhââ ce projet me prends la tête je commence à n'y plus rien comprendre à ces histoires de moniteurs. Moi en plus je veux pas bloquer les méthodes je veux juste utiliser wait et notifyAll( )

    Comment je peux faire ça peinard?
    Linio

  15. #15
    Membre régulier

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 84
    Points : 75
    Points
    75
    Par défaut
    En Java, pour assurer qu'un code ne sera exécuté que par un seul thread simultanément on utilise des moniteurs qui sont en fait une section critique délimité par le mot clef synchronised.

    Par exemple, si un thread B cherche à accèder à un code protégé par un moniteur sur l'objet toto alors qu'un thread A est déjà dans dans une section de code protégé par ce moniteur sur toto (ce n'est pas obligatoirement le même code). Et bien le thread B est alors mis en attente. Il ne reprendra la main que quand la jvm le lui redonnera, c'est à dire quand le thread A aura relaché son moniteur sur toto :
    - soit en sortant de la portion de code définie comme synchronised(toto)
    - soit en se placant en wait (http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#wait())

    Voili voulou j'espère avoir été clair

  16. #16
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    Tout à fait clair.
    Ce que je ne comprends pas alors, c'est comment peut fonctionner un notifyAll(), puisque celui ci doit se trouver dans une portion de code synchronisé, il ne pourra jamais être exécuté et de fait réveiller le thread A bloqué dans un wait de ce même objet...?
    Linio

  17. #17
    Membre régulier

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 84
    Points : 75
    Points
    75
    Par défaut
    c'est à dire quand le thread A aura relaché son moniteur sur toto :
    - soit en sortant de la portion de code définie comme synchronised(toto)
    - soit en se placant en wait (http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#wait())
    Si tu vas voir l'url que je t'ai donnée, tu pourras voir quand un thread A est bloqué sur un wait il relache le moniteur sur l'objet toto, ce qui veux dire qu'un autre thread B peut rentrer dans une section critique et faire un notify, le thread A se débloque mais attend que le thread B redonne le moniteur sur l'objet toto pour le rependre et continuer son exécution après le wait.

    Comme on est jamais à l'abris d'un notify mal placé, Sun conseille de n'utiliser l'instruction wait uniquement dans une boucle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    while(!finduwait){
     wait();
    }
    C'est marrant parceque je me suis posé les même question dernièrement, je pense que je vais écrire une correction à la FAQ pour éclairsir ce point de la gestion des thread en Java.

  18. #18
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    Merci. Le coup du relachage du moniteur voilà ça m'était pas trivial.
    Bon c'est plus clair, je sais pas si ça m'aidera pour mon projet qui semble marcher au petit bonheur, mais maintenant je vois comment ça fonctionne.
    Merci.

    Une dernière question cependant. Quand un thread quitte une méthode synchronisée ceux qui étaient en attente sur le même moniteur peuvent s'exécuter automatiquement où il faut les notifier?
    Linio

  19. #19
    Membre régulier

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 84
    Points : 75
    Points
    75
    Par défaut
    Biensur, les thread en attente sur la section critique seont notifié automatiquement. Par contre je ne sais pas comment fonctionne la gestion de priorité entre les threads (à qui la jvm donne la main quand plusieurs thread sont en attente ?)

  20. #20
    Membre averti Avatar de Linio
    Inscrit en
    Octobre 2005
    Messages
    431
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 431
    Points : 332
    Points
    332
    Par défaut
    Ok.

    Bon ben mon programme est sensé fonctionner alors mais en fait non
    Bon au moins j'aurais fait ce que j'ai pu tant pis.

    Merci pour le coup de main en tout cas.
    Linio

Discussions similaires

  1. problème Synchronisation Threads
    Par leconteconte dans le forum Général Java
    Réponses: 2
    Dernier message: 01/01/2013, 16h47
  2. Problème synchronisation Thread()
    Par Anduriel dans le forum Android
    Réponses: 2
    Dernier message: 21/05/2012, 17h15
  3. Problème synchronisation thread
    Par Tinkh dans le forum Bibliothèques, systèmes et outils
    Réponses: 2
    Dernier message: 27/01/2011, 10h34
  4. [WPF] Circular ProgressBar, problème synchronisation des threads
    Par Babas007 dans le forum Windows Presentation Foundation
    Réponses: 6
    Dernier message: 20/12/2010, 19h44
  5. [THREAD] Problème synchronisation
    Par goddet dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 25/10/2006, 09h16

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