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

Langage Java Discussion :

Question d'implémentation: boucle active [FAQ]


Sujet :

Langage Java

  1. #1
    Membre à l'essai
    Inscrit en
    Octobre 2005
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 28
    Points : 13
    Points
    13
    Par défaut Question d'implémentation: boucle active
    Bonjour j'ai un petit problème d'implémentation. Je veux a tout prix éviter de laisser une boucle active dans mon programme, j'avais trouvé une solution intéressant mais finalement non...
    Mon application doit pouvoir enregister un certain nombre de requete qui seront geré par un autre thread. Ce thread ne doit pas tourner a l'infini si la liste de requete est vide mais s'endormir et se reveillée dès qu'une requete est enregistrée.
    ce que je voudrais eviter :
    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
     
    class A implements Runnable {
       private ConcurrentLinkedQueue<Search> gSearches;
     
       A {
         gSearchs = new  ConcurrentLinkedQueue<Search>();
         new Thread(this, "SearchManager").start();
       }
     
       void run() {
          while (true) {
             Search tmp;
             if ((tmp == gSearches.poll()) != null) {
               // traitement de la recherche
             }
          }
       }
     
       public void registerSearch(Search toRegister) {
          gSearches.add(toRegister);
       }
    }
    Le problème avec cette méthode c'est que j'ai une boucle active dans mon thread ce qui est tres mauvais pour les performances.

    Premiere solution:
    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
     
    class A implements Runnable {
       private ConcurrentLinkedQueue<Search> gSearches;
       private Lock gLock;
       private Condition gFillList;
     
       A {
         gSearchs = new  ConcurrentLinkedQueue<Search>();
         gLock = new ReentrantLock();
         gFillList = gLock.newCondition();
         new Thread(this, "SearchManager").start();
       }
     
       void run() {
          gLock.lock();
          try {
                while (true) {
                    Search mCurrentSearch;
                    while ((mCurrentSearch = gSearches.poll()) == null) // gestion des spurious wakeup
                        gFillList.await();
                    // gestion de la recheche.
                }
          }
          catch (InterruptedException e) {
            // gestion...
          }
          finally() {
            gLock.unlock();
          }
       }
     
       public void registerSearch(Search toRegister) {
            gSearches.add(toRegister);
            gLock.lock();
            gFillList.signal();
            gLock.unlock();
       }
    }
    Je pensais régler mon problème en utilisant cette méthode mais le problème est que si le traitement de la recherche est long et que j'essaye d'enregistrer une autre recherche pendant qu'une recherche est en cours, la récupération du lock me bloque.
    javadoc:
    If the lock is held by another thread then the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been acquired, at which time the lock hold count is set to one.
    Comment faire ?

  2. #2
    Expert éminent sénior
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Points : 12 977
    Points
    12 977
    Par défaut
    Eventuellement tu peux passer par un synchronized pour éviter que deux threads se bousculent au niveau de la recherche
    Hey, this is mine. That's mine. All this is mine. I'm claiming all this as mine. Except that bit. I don't want that bit. But all the rest of this is mine. Hey, this has been a really good day. I've eaten five times, I've slept six times, and I've made a lot of things mine. Tomorrow, I'm gonna see if I can't have sex with something.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    509
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 509
    Points : 568
    Points
    568
    Par défaut
    Salut,
    tu dois pouvoir faire ca avec les methodes wait et notify de la classe Object .
    sur un objet partager (par exemple la liste) tu peux appeler wait dans le thread qui traite les requete et l'autre thread appelle Notify a chaque fois qu'il ajoute une requete .
    Enfin j'ai lu rapidement ton probleme donc peut etre que mon exemple n'est pas parfaitement ce que tu recherche mais je pense qu'une solution pourrais etre d'utiliser wait et notify :
    http://www.lifl.fr/~bogaert/clfc/polyDurif/node84.html

    a toi de voir
    UML avec VIOLET

  4. #4
    Gfx
    Gfx est déconnecté
    Expert éminent
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Points : 8 178
    Points
    8 178
    Par défaut
    Tu peux aussi rajouter un Thread.yield() ou un Thread.sleep() dans ta boucle active.
    Romain Guy
    Android - Mon livre - Mon blog

  5. #5
    Membre à l'essai
    Inscrit en
    Octobre 2005
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 28
    Points : 13
    Points
    13
    Par défaut
    J'ai essayé de faire ca avec des wait et des notify mais j'ai une exception.

    Nouveau code:
    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
     
    class A implements Runnable {
       private ConcurrentLinkedQueue<Search> gSearches;
       private Lock gLock;
       private Condition gFillList;
     
    private Thread TEST;
     
       A {
         gSearchs = new  ConcurrentLinkedQueue<Search>();
         gLock = new ReentrantLock();
         gFillList = gLock.newCondition();
         TEST = new Thread(this, "SearchManager");
         TEST.start();
       }
     
       void run() {
          try {
                while (true) {
                    Search mCurrentSearch;
                    while ((mCurrentSearch = gSearches.poll()) == null) // gestion des spurious wakeup
                        wait(); //  le wait
                    // gestion de la recheche.
                }
          }
          catch (InterruptedException e) {
            // gestion...
          }
       }
     
       public void registerSearch(Search toRegister) {
            gSearches.add(toRegister);
            TEST.notify();
       }
    }
    Exception
    Exception in thread "SearchManager" java.lang.IllegalMonitorStateException: current thread not owner
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:474)
    at xxx.SearchManager.run(SearchManager.java:75)
    at java.lang.Thread.run(Thread.java:595)
    J'avais deja essayé cette technique mais j'avais laissé tombé a cause de cette erreur

  6. #6
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    entour ton wait d'un bloc synchronizé ;-)
    ==>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    synchronized(this) {
     wait();
    }

  7. #7
    Membre à l'essai
    Inscrit en
    Octobre 2005
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 28
    Points : 13
    Points
    13
    Par défaut
    Ca déplace l'exception maintenant elle est au niveau du notify (qui se fait dans un autre thread).
    J'ai aussi essayé de le faire dans un bloc synchronisé mais :
    Exception in thread "Thread-1" java.lang.IllegalMonitorStateException: current thread not owner
    at java.lang.Object.notify(Native Method)
    at xxx.SearchManager.registerSearch(SearchManager.java:108)
    ...

  8. #8
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    c'est normal, je peux voir ton code stp? comment tu synchronize au niveau de ton notify...

  9. #9
    Membre à l'essai
    Inscrit en
    Octobre 2005
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 28
    Points : 13
    Points
    13
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        public void registerSearch(Search pSearchToRegister) {
            gSearchesTodo.add(pSearchToRegister);
            synchronized (TEST) { TEST.notify(); }
    ne réveille pas le thread qui parcours ma liste.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        public void registerSearch(Search pSearchToRegister) {
            gSearchesTodo.add(pSearchToRegister);
            synchronized (this) { TEST.notify(); }
        }
    génère l'exception.

  10. #10
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    le premier ne reveille pas le thread car quelqu'un d'autre à déjà le lock (le thread lui même en fait...)

    ce que tu peux faire c'est créer une méthode wake, dans ton thread et faire le notify à partir de là en appelant wake genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public void wake() {
            synchronized (this) {
     
                this.notify();
     
            }
     
        }
    dans ta classe A.

  11. #11
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    l'explication est assez simple et logique. Un objet qui a un lock sur un objet peut appeller d'autres méthodes synchronizées de cet objet (heu je suis clair? :-p)

  12. #12
    Membre à l'essai
    Inscrit en
    Octobre 2005
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 28
    Points : 13
    Points
    13
    Par défaut
    Mais dans ce cas c'est assez bizare puisque ma methode registerSearch est dans ma classe A

  13. #13
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    bah non :-)
    juste dans ta méthode registerSearch tu appelleras "TEST.wake()" au lieu de "TEST.notify()"...

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


    La première solution avec les Lock et les Condition me semble correcte d'après la documentation de l'interface Condition (mis à part quelques petites fautes de frappes).

    Sauf peut-être que le unlock doit toujours être dans un bloc finally quoi qu'il arrive :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    gLock.lock();
    try {
            gFillList.signal();
    } finally {
            gLock.unlock();
    }


    Quel est le comportement que tu obtiens avec cette méthode ?

    a++

  15. #15
    Membre à l'essai
    Inscrit en
    Octobre 2005
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 28
    Points : 13
    Points
    13
    Par défaut
    Merci a toi bidi ca fonctionne.
    Parcontre je vais quand meme voir si je peux faire ca avec des conditions.
    Au moin si ce n'est vraiment pas possible de le faire avec j'ai une solution (et en plus j'ai appris d'ou venait cette exception)

  16. #16
    Membre à l'essai
    Inscrit en
    Octobre 2005
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 28
    Points : 13
    Points
    13
    Par défaut
    Le problème avec les conditions:

    quand je démarre mon thread de parcours de recherche enregistrée puisque la liste est vide il se met en await.
    J'enregistre une recherche -> mon thread de parcours se reveille, je sors de ma méthode d'enregistrement et la recherce se lance.
    si j'enregistre une autre recherche pendant que la premiere recherche est encore en cours, la récuperation du lock bloque -> je dois attendre la fin de l'exécution de ma première recherche pour sortir de ma méthode d'enregistrement.
    (j'espere que c'est clair)

  17. #17
    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
    Citation Envoyé par addack
    (j'espere que c'est clair)
    Oui c'est très clair

    je pense voir d'où ca peut venir...

    Je suppose que le traitement d'une recherche peut prendre un certain temps, et du coups dans ta méthode registerSearch() tu n'arrives pas à obtenir le lock puisqu'il est pris par le thread de traitement... Du coups tu te retrouve bloqué afin d'attendre d'envoyer le signal alors que le thread est déjà en cours d'exécution, et il te faut attendre qu'il rentre dans await() afin qu'il libère le lock... ce qui retardera d'autant tes ajouts...




    Je vois deux solutions :

    Soit la méthode signal() n'a pas besoin d'être synchronisé (même si c'est le cas dans l'exemple de la javadoc, je ne vois rien de tel qui dit que c'est obligatoire), et dans ce cas il te suffirai de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public void registerSearch(Search toRegister) {
            gSearches.add(toRegister);
            gFillList.signal();
    }

    Soit il faut que signal() soit également synchronisé, et dans ce cas tu peux t'en sortir avec un tryLock() (qui ne bloque pas si il ne peut pas prendre la main) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public void registerSearch(Search toRegister) {
            gSearches.add(toRegister);
     
    	if (gLock.tryLock()) {
    		try {
    			gFillList.signal();
    		} finally {
    			lock.unlock();
    		}
    	}
    }
    Mais dans ce cas tu peux avoir un problème si tu ajoute l'élément juste avant l'appel de await() dans l'autre thread, et sortir de la méthode registerSearch() alors que le thread de traitement vient de se mettre en attente...

    Dans ce cas il faudrait peut être rajouter une vérification de la taille de la liste avant de forcer un autre lock()...




    Tiens nous au courant...

    a++

  18. #18
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    c'est un Reentrant lock, donc la méthode signal ne sera pas bloquée par le lock ds le run...
    Par contre, le problème est que telle que tu l'as décrite, ton applic n'est pas multithreadée pour un sous... tu fais un lock au début du run et tu l'enlève à la fin...2 traitements ne pourront donc jamais s'exécuter en même temps! change la granularité de ton lock et ça ira déjà bcp mieux (normalement ;-)

  19. #19
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    en gros, tu mets les lock au même niveau que les synchronized ds ton autre exemple. Si ça marche avec les synchronized ça devrait marcher avec les Lock vu qu'ils ont quasiment le même comportement...

  20. #20
    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
    Citation Envoyé par bidi
    c'est un Reentrant lock, donc la méthode signal ne sera pas bloquée par le lock ds le run...
    Tu pourrais expliquer cela ca m'intérresse...

    Citation Envoyé par bidi
    Par contre, le problème est que telle que tu l'as décrite, ton applic n'est pas multithreadée pour un sous... tu fais un lock au début du run et tu l'enlève à la fin...2 traitements ne pourront donc jamais s'exécuter en même temps! change la granularité de ton lock et ça ira déjà bcp mieux (normalement ;-)
    Tu veux sans doute dire synchronisé et pas multithreadé
    Mais tu as raison puisque le try sur l'ensemble est inutile puisque seule l'attente doit être synchronisé...
    Ceci serait plus correct :
    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
    public void run() {
    	while (true) {
    		Search mCurrentSearch;
     
    		gLock.lock();
    		try {
    			while ((mCurrentSearch = gSearches.poll()) == null) {
    				gFillList.await();
    			}
    		} finally {
    			gLock.unlock();
    		}
     
    		// Traitement ici
       }
    }
     
     
    public void registerSearch(Search toRegister) {
    	gSearches.add(toRegister);
    	gLock.lock();
    	try {
    		gFillList.signal();
    	} finally {
    		lock.unlock();
    	}
    }
    Dans ce cas la méthode registerSearch() peut acquérir le lock lorsque le thread effectue ses traitements (puisqu'ils ne sont plus en zone synchronisé).

    Le seul cas où la méthode registerSearch() peut se retrouver bloqué, c'est si le thread est dans la boucle while() d'await(), et on a alors deux cas :
    • Soit il y a encore des éléments et le thread libère le lock, et donc la méthode registerSearch() le récupère...
    • Soit il n'y a plus d'élément et le thread rentre dans await() et libère donc le lock...


    a++

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Question sur Update et Active =true
    Par Hurin dans le forum Bases de données
    Réponses: 3
    Dernier message: 29/06/2008, 08h33
  2. Réponses: 5
    Dernier message: 16/06/2008, 22h00
  3. Réponses: 2
    Dernier message: 07/05/2007, 16h46
  4. question sur une boucle et un break
    Par isidore dans le forum C
    Réponses: 10
    Dernier message: 22/11/2006, 20h26

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