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

Java Discussion :

Thread & Lock - fil d'execution


Sujet :

Java

  1. #1
    Membre habitué Avatar de Jose.N70
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2009
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2009
    Messages : 162
    Points : 130
    Points
    130
    Par défaut Thread & Lock - fil d'execution
    Bonjour, pourriez vous m'éclairer sur un point que j'ai du mal à comprendre et donc à résoudre :

    J'ai une liste ( Arraylist d'objets ) que je dois traiter ( traitement de données sur un serveur distant ) au fur et à mesure.

    J'ai un Thread qui va faire ce traitement ( tache asynchrone ) un objet à la fois et qui doit se bloquer une fois réalisé en attendant le retour du serveur.

    J'ai un second Thread qui va recevoir les données du serveur, dès que celui ci à reçu le traitement de l'objet traité dans le thread 1, il doit lui dire de passer à l'objet suivant

    Je pensais utiliser ReentrantLock avec une Condition mais je dois peut être mal m'y prendre

    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
     
    	private Lock lock = new ReentrantLock();
    	private Condition next = lock.newCondition();
    ...
    ...
    monThread = new Thread(new Runnable() {
     
    	@Override
    	public void run() {
                lock.lock();
     
                 try{
                      for(MonObjet o : maListe){
                           traitement(o);
                           next.await();
                      }
     
                 }
                 finally {
                      lock.unlock();
                 }
     
            }
    }
    et le second thread qui lui doit débloquer le thread1

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public void run() {
     // traitement code retour serveur 
     next.notify();
    }

    Une erreur est levée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    java.lang.IllegalMonitorStateException: object not locked by thread before notify()
    at java.lang.Object.notify(Native Method)
    at fr.test.Utils.updateStatus(Utils.java:300) //  next.notify();
    at fr.test.Utils.access$13(Utils.java:293)
    at frtest.Utils$7.run(Utils.java:287)
    at java.lang.Thread.run(Thread.java:841)
    Merci pour votre aide

  2. #2
    Membre du Club
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Novembre 2013
    Messages : 49
    Points : 68
    Points
    68
    Par défaut
    Bonjour,

    Normalement tu devrais avoir une erreur dans ton IDE (si tu en utilises un). Dans tous les cas Condition ne connait pas la méthode notify() il te faut donc utiliser signal() pour réveiller next

  3. #3
    Membre habitué Avatar de Jose.N70
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2009
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2009
    Messages : 162
    Points : 130
    Points
    130
    Par défaut
    L'erreur levée se trouve dans mon premier message ( dans la partie du bas ).
    Pour notify ou signal le résultat reste le même

  4. #4
    Membre du Club
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Novembre 2013
    Messages : 49
    Points : 68
    Points
    68
    Par défaut
    Non je parlais pas de l'erreur levée mais d'une erreur d'"écriture" si tu préfères : wait et notify sont des méthodes appartenant à la classe Object et définit donc toutes les classes qui vont hériter de Object (autrement dit, toutes) sauf pour les interfaces : Condition est une interface et par définition ne peut pas hérité d'Object donc elle ne peut pas connaître les méthodes wait et notify. De plus Condition a été créé pour remplacer ces méthodes là. Donc tu peux oublier notify

    D'après l'erreur levée, tu ne "lock" pas ton next.signal(). Lock est une alternative à synchronized donc tu dois "locker" avec le même objet Lock ta partie du code avec await et ta partie du code avec signal

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

    Comme pout wait et notify, pour await et signal, les threads appelant ces méthodes doivent avoir le "monitor" sur l'instance sur laquelle on invoque ces méthode (avoir le monitor signifie que le thread doit avoir l'exclusivité d'accès, ce qui se fait par la pose d'un verrou (par synchronized avec wait/notify, et par lock/unlock pour les XXXLock).

    Exemple d'une classe de gestion de buffer :

    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
    public class BoundedBuffer<T> {
        private final Object[] buffer; // buffer
        private final int capacity; // taille du buffer
     
        private int readPosition; // prochaine position où on va écrire
        private int writePosition; // prochaine position à lire (si le buffer n'est pas vide)
        private int count; // nombre d'éléments dans le buffer
     
        private final Lock lock = new ReentrantLock(); // verrou permettant de ne pas lire et écrire en même temps
     
        private final Condition read = lock.newCondition(); // condition permettant d'attendre qu'on puisse lire
        private final Condition write = lock.newCondition(); // condition permettant d'attendre qu'on puisse écrire
     
        /**
         * Créer un buffer FIFO de taille fixe
         * @param capacity
         */
        public BoundedBuffer(int capacity) {
            super();
            this.capacity = capacity;
            buffer = new Object[capacity];
        }
     
        /**
         * Mettre une donnée dans le buffer
         * @param data
         * @throws InterruptedException
         */
        public void write(T data) throws InterruptedException {
     
        	lock.lock(); // on demande le verrou
            try {
                while (count == capacity) { // tant que le buffer est plein (on ne peut pas écrire, alors on attend que des positions se libèrent)
                    read.await(); // le thread attend un signal ou qu'il soit "interrupted" (on relache le verrou, ce qui permet à la méthode de lecture de lire le buffer)
                }
                buffer[writePosition] = data; // on stocke la donnée
                writePosition = (writePosition + 1) % capacity; // on se positionne sur la prochaine position libre (le module fait que quand on atteint la taille du buffer, on "boucle" sur le début
                count++; // on compte la donnée stockée
                write.signal(); // on avertit le thread de lecture qu'il y a quelque chose dans le buffer (s'il était en attente qu'on mette quelque chose dans le buffer
            } finally {
                lock.unlock(); // on relâche le verrou
            }
     
        }
     
        /**
         * Lire une donnée présente dans le buffer
         * @return
         * @throws InterruptedException
         */
        public T read() throws InterruptedException {
     
        	lock.lock(); // on demande le verrou
            try {
                while (count == 0) { // tant que le buffer est vide, il n'y a rien à lire, alors on attend
                    write.await(); // le thread attend un signal ou qu'il soit "interrupted" (on relache le verrou ce qui permet à la méthode d'écriture d'écrire dans le buffer) 
                }
     
                @SuppressWarnings("unchecked")
    			T result = (T)buffer[readPosition]; // on lit la donnée dans le buffer
     
                readPosition = (readPosition + 1) % capacity; // on se positionne sur la prochaine donnée dans le buffer
                count--; // on décompte la donnée lue
     
                read.signal(); // on avertit le thread d'écriture qu'on a lu une donnée (s'il est en attente parce que le buffer était plein, il va pouvoir écrire) 
     
                return result;
            } finally {
                lock.unlock(); // on relâche le verrou
            }
        }
     
    }
    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.

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 608
    Points
    21 608
    Par défaut
    Citation Envoyé par SamusStrife Voir le message
    Non je parlais pas de l'erreur levée mais d'une erreur d'"écriture" si tu préfères : wait et notify sont des méthodes appartenant à la classe Object et définit donc toutes les classes qui vont hériter de Object (autrement dit, toutes) sauf pour les interfaces : Condition est une interface et par définition ne peut pas hérité d'Object donc elle ne peut pas connaître les méthodes wait et notify.
    La prochaine fois essaie d'abord, ça compile parfaitement -_-°.
    En Java la classe Object est particulière : les interfaces sont toutes sous-type d'Object (tous les types références, ceux qui peuvent être pointeurs null, sont sous-type d'Object.) On peut faire avec une interface tout ce qu'on peut faire avec un Object, donc entre autres, appeler wait() et notify().

    ... Par contre, le fait est que les Lock sont justement faits pour utiliser un autre mécanisme que wait() et notify(), mais bon, ça résout pas le problème, et non, l'IDE va pas le deviner -_-°.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre habitué Avatar de Jose.N70
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2009
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2009
    Messages : 162
    Points : 130
    Points
    130
    Par défaut
    Citation Envoyé par joel.drigo Voir le message
    Salut,

    Comme pout wait et notify, pour await et signal, les threads appelant ces méthodes doivent avoir le "monitor" sur l'instance sur laquelle on invoque ces méthode (avoir le monitor signifie que le thread doit avoir l'exclusivité d'accès, ce qui se fait par la pose d'un verrou (par synchronized avec wait/notify, et par lock/unlock pour les XXXLock).

    Exemple d'une classe de gestion de buffer :

    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
    public class BoundedBuffer<T> {
        private final Object[] buffer; // buffer
        private final int capacity; // taille du buffer
     
        private int readPosition; // prochaine position où on va écrire
        private int writePosition; // prochaine position à lire (si le buffer n'est pas vide)
        private int count; // nombre d'éléments dans le buffer
     
        private final Lock lock = new ReentrantLock(); // verrou permettant de ne pas lire et écrire en même temps
     
        private final Condition read = lock.newCondition(); // condition permettant d'attendre qu'on puisse lire
        private final Condition write = lock.newCondition(); // condition permettant d'attendre qu'on puisse écrire
     
        /**
         * Créer un buffer FIFO de taille fixe
         * @param capacity
         */
        public BoundedBuffer(int capacity) {
            super();
            this.capacity = capacity;
            buffer = new Object[capacity];
        }
     
        /**
         * Mettre une donnée dans le buffer
         * @param data
         * @throws InterruptedException
         */
        public void write(T data) throws InterruptedException {
     
        	lock.lock(); // on demande le verrou
            try {
                while (count == capacity) { // tant que le buffer est plein (on ne peut pas écrire, alors on attend que des positions se libèrent)
                    read.await(); // le thread attend un signal ou qu'il soit "interrupted" (on relache le verrou, ce qui permet à la méthode de lecture de lire le buffer)
                }
                buffer[writePosition] = data; // on stocke la donnée
                writePosition = (writePosition + 1) % capacity; // on se positionne sur la prochaine position libre (le module fait que quand on atteint la taille du buffer, on "boucle" sur le début
                count++; // on compte la donnée stockée
                write.signal(); // on avertit le thread de lecture qu'il y a quelque chose dans le buffer (s'il était en attente qu'on mette quelque chose dans le buffer
            } finally {
                lock.unlock(); // on relâche le verrou
            }
     
        }
     
        /**
         * Lire une donnée présente dans le buffer
         * @return
         * @throws InterruptedException
         */
        public T read() throws InterruptedException {
     
        	lock.lock(); // on demande le verrou
            try {
                while (count == 0) { // tant que le buffer est vide, il n'y a rien à lire, alors on attend
                    write.await(); // le thread attend un signal ou qu'il soit "interrupted" (on relache le verrou ce qui permet à la méthode d'écriture d'écrire dans le buffer) 
                }
     
                @SuppressWarnings("unchecked")
    			T result = (T)buffer[readPosition]; // on lit la donnée dans le buffer
     
                readPosition = (readPosition + 1) % capacity; // on se positionne sur la prochaine donnée dans le buffer
                count--; // on décompte la donnée lue
     
                read.signal(); // on avertit le thread d'écriture qu'on a lu une donnée (s'il est en attente parce que le buffer était plein, il va pouvoir écrire) 
     
                return result;
            } finally {
                lock.unlock(); // on relâche le verrou
            }
        }
     
    }

    En relisant ton code je comprends mieux mon problème et pense pouvoir le résoudre assez facilement.

    Un grand merci à toi

  8. #8
    Membre du Club
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Novembre 2013
    Messages : 49
    Points : 68
    Points
    68
    Par défaut
    Citation Envoyé par thelvin Voir le message
    La prochaine fois essaie d'abord, ça compile parfaitement -_-°.
    En Java la classe Object est particulière : les interfaces sont toutes sous-type d'Object (tous les types références, ceux qui peuvent être pointeurs null, sont sous-type d'Object.) On peut faire avec une interface tout ce qu'on peut faire avec un Object, donc entre autres, appeler wait() et notify().
    Ha ok j'éviterai de refaire cette erreur à l'avenir j'étais persuadé que comme une interface ne pouvait avoir de constructeur elle ne pouvait être lié à Object mais dit comme ça, ça parait logique... Désolé encore pour ma maladresse

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

Discussions similaires

  1. [Multi-thread] Comment lock l'acces a un containeur de la STL ?
    Par Izidor's dans le forum Threads & Processus
    Réponses: 5
    Dernier message: 14/10/2009, 12h09
  2. Thread et lock pour écrire dans un fichier?
    Par DarkHerumor dans le forum C#
    Réponses: 3
    Dernier message: 31/03/2009, 09h40
  3. Thread et lock de tables
    Par babylone7 dans le forum Oracle
    Réponses: 6
    Dernier message: 27/06/2006, 17h31
  4. [Thread] Connaitre la fin d'execution d'un thread
    Par charmante dans le forum Concurrence et multi-thread
    Réponses: 6
    Dernier message: 05/10/2005, 18h57

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