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 :

Synchronisation à l'intérieur d'une méthode


Sujet :

Langage Java

  1. #1
    Membre du Club
    Inscrit en
    Mai 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 71
    Points : 52
    Points
    52
    Par défaut Synchronisation à l'intérieur d'une méthode
    Bonjour à tous,

    j'ai une classe chargé de mettre à jour des informations pour un fond, un OPCVM, une SICAV (ça peut très bien être un client ou quelque chose d'autre).

    Les méthodes de cette classe, par souci de simplification, sont statiques.

    Bref ça doit ressembler à ça :

    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
     
    public class MaClasse{
     
    static public void effectueTraitement(Dao monDao, int idFonds){
     
    // quelques traitements prealables 
     
    if(faireTraitement1Ou2){
    effectueTraitementNo1(monDao, idFonds);
    }else{
    effectueTraitementNo2(monDao, idFonds);
    }
    }
     
    static private effectueTraitementNo1(Dao monDao, int idFonds){
    }
     
    static private effectueTraitementNo2(Dao monDao, int idFonds){
    }
    }
    Mon désir est de bloquer le traitement à effectuer pour UN fond, en cas de multithreading (on ne sait jamais).
    Donc je ne veut pas ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    static public synchronised void effectueTraitement(Dao monDao, int idFonds){
    Mais plutôt ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    static public void effectueTraitement(Dao monDao, int idFonds){
    // trouver un objet pour se synchroniser
    synchronised (monObjet){ // car "synchronised(idFonds)" ça ne marche pas
    // ...
    }
    }

    Alors ?
    Comment faire ?

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 238
    Points : 267
    Points
    267
    Par défaut
    Salut,

    Ben ta méthode étant static il suffit de déclarer un objet static :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    private static Object mutex = new Object ();
    ...
    static public void effectueTraitement(Dao monDao, int idFonds){
        synchronised (mutex) {
            // Tes traitements...
        }
    }
    Par contre je ne comprent pas pourquoi tu ne souhaite pas synchroniser la méthode complète...

    Voila a+

  3. #3
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Euh ... non là je pense que ta solution ne répond pas à la question...
    En fait, il veut synchroniser toutes ses méthodes de traitement ensemble pour éviter qu'on puisse faire deux traitements sur le même id en même temps, c'est bien ça ?

    Si c'est ça, alors effectivement c'est un peu embêtant car tu n'as pas un objet, mais un type primitif (id).

    Il faudrait d'une certaine manière associer un objet à chaque id. Le problème, c'est la consommation mémoire, car je ne vois pas trop comment gérer la libération de ces objets (cad comment savoir qu'on a plus de thread en traitement sur cet id) ...

  4. #4
    Membre du Club
    Inscrit en
    Mai 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 71
    Points : 52
    Points
    52
    Par défaut
    Oui c'est exactement ça ...
    Eviter de faire que 2 threads fassent le même traitement sur le même id !!!

    Et pourquoi pas ça :

    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
     
     
    static private Map mapMutexByID = new Hashtable();
     
    static public void Object getMutexByIdFonds(int idFonds){
        Integer intId = new Integer(idFonds);
        if(!mapMutexByID.contains(intId){
            mapMutexByID .put(intId, new Object());
        }
        Object obj = mapMutexByID.get(intId);
    }
     
    static public void effectueTraitement(Dao monDao, int idFonds){
        synchronised (getMutexByIdFonds(idFonds)) {
            // Traitements...
        }
    }
    Qu'en pensez vous ?
    Pour chaque idFonds, on n'instance qu'un objet et on le récupère pour l'utiliser comme Mutex.

  5. #5
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Pourquoi pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    ...
    synchronized (tonObjet)
    {
       ... le code ...         
    }
    ...

  6. #6
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    @OButterlin : pas compris ...
    @Péchereau : oui, ça peut marcher, à condition tout de même de synchroniser la méthode getMutexByIdFonds. Mais le souci c'est que si tu as des millions d'ids possibles tu vas te retrouver à terme avec des millions d'objets créés pour la synchro .... C'est ce que je voulais dire auparavant en disant qu'on ne sait pas quand les libérer.

  7. #7
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    A l'intérieur d'une méthode, tout ce qui se trouve à l'intérieur du bloc synchronized nécessite le verrou sur l'objet "tonObjet"
    Donc, avec 2 Threads, un seul ne passe à la fois dans le bloc...

    C'est ce que tu voulais non ?

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 238
    Points : 267
    Points
    267
    Par défaut
    Salut,

    en effet je n'avai pas bien lu ta question.
    La réponse de Péchereau me semble adaptée.
    Par contre en effet si il y a de très nombreux Fond tu aura autant d'objet créent et qui ne seront jamais libérés....

    Je ne connait pas du tout l'architecture de ton application, mais si au lieu d'avoir une classe qui effectue tous les traitements dans des méthodes statiques tu ajoutais la possibilité aux objets eux-mêmes de s'enregistrer et que tu développaient un scheduler qui prennent lui en charge la synchronisation.......lol je sais pas si sais clair et si c'est possible pour ton application, c'est juste une idée...

    a+

  9. #9
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Citation Envoyé par OButterlin
    A l'intérieur d'une méthode, tout ce qui se trouve à l'intérieur du bloc synchronized nécessite le verrou sur l'objet "tonObjet"
    Donc, avec 2 Threads, un seul ne passe à la fois dans le bloc...

    C'est ce que tu voulais non ?
    Ben il ne s'agit pas de savoir ce que fait synchronized (je crois que tous les gens qui sont intervenus le savent) mais de résoudre le souci d'origine ....
    En l'occurence, dans ton post, on ne sait pas du tout ce que c'est que monObjet ...

  10. #10
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    En fait j'étais à l'ouest !
    Pourquoi veux-tu synchroniser la méthode getMutexByIdFonds ?
    Même si potentiellement tu peux accéder 2 fois à cette méthode, tu ne peux entrer qu'une fois dans le verrou pour un même id

  11. #11
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Pas facile d'illustrer ce que peuvent donner deux Threads qui "tombent mal", mais je vais essayer.

    Imaginons que la méthode soit codée ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    static public void Object getMutexByIdFonds(int idFonds){
        Integer intId = new Integer(idFonds);
        if(!mapMutexByID.contains(intId){
            mapMutexByID .put(intId, new Object());
        }
        Object obj = mapMutexByID.get(intId);
    }
    et soit appelée "en même temps" par thread1 et thread2 avec le même id (1).

    thread1 exécute :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    static public void Object getMutexByIdFonds(int idFonds){
        Integer intId = new Integer(idFonds);
        if(!mapMutexByID.contains(intId){
    Là la main passe à thread2. A noter que pour thread1 le test est faux donc thread1 finira par créer un Integer pour l'id 1.
    thread2 exécute ensuite
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    static public void Object getMutexByIdFonds(int idFonds){
        Integer intId = new Integer(idFonds);
        if(!mapMutexByID.contains(intId){
    Le test est également faux pour thread2.

    Donc au final, thread1 et thread2 vont tous les deux créer un Integer pour l'id 1 et ne seront pas synchronisés alors qu'ils manipulent le même id.

    CQFD (enfin j'espère que mon explication a été assez claire)

  12. #12
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    C'est très clair et effectivement, il n'y a que la synchro de la méthode getMutexByIdFonds(int) qui l'évitera

  13. #13
    Membre du Club
    Inscrit en
    Mai 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 71
    Points : 52
    Points
    52
    Par défaut
    Merci à tous de vos éclaircissements.

    Effectivement il faut aussi rendre "synchronized" la méthode getMutexByIdFonds(int)"; même si le problème de la libération de l'objet Integer associé au fond est problématique ...
    A la fin, je risque de me retrouver avec une "Map" d'Integer fort importante (comme la 2sde loi de la dynamique, elle ne peut que crôitre).

    @Kh4iN3 : en fait, pour etre exact, j'effectue un ensemble d'opérations liées au fonds en question (lignes de Valeur Liquidative, performances ...), mais pas nécessairement au fonds lui même. Je ne sais pas si je suis bien clair là ...

  14. #14
    Membre du Club
    Inscrit en
    Mai 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 71
    Points : 52
    Points
    52
    Par défaut
    Précision :
    je ne sais si ça ça marcherait ...

    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
     
     
    public static synchronized removeMutexByID(int idFonds){
        mapMutexByID.remove(new Integer(idFonds));
    }
     
    static public void effectueTraitement(Dao monDao, int idFonds){
        synchronised (getMutexByIdFonds(idFonds)) {
            try{
                 // faire traitement ... 
            }catch(Throwable t){
                 throw t;
            }finally{
                 removeMutexByID(idFonds);
            }
        }
    }
     
    // autres methodes ...
    ???

  15. #15
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Non, j'avais pensé à ça, mais c'est vrai que j'aurais pu expliquer pourquoi je disais qu'on ne pouvait pas supprimer les objets.

    En fait, le souci vient maintenant si tu as trois Thread qui veulent faire des choses sur le même id 1.

    Imaginons :
    thread1 commence : l'objet est donc créé et la map contient un Integer 1. Il commence son traitement et est interrompu.
    thread2 prend la main : la map contient bien l'integer 1 donc thread2 se met en attente.
    thread1 termine son traitement, et remove l'objet Integer 1 de la map.
    thread2 est donc réveillé et commence son traitement. Il est interrompu.
    thread3 arrive et n'est pas bloqué car la map ne contient plus d'integer 1.

    thread2 et thread3 vont donc effectuer des traitements en parallèle sur le même id :-((

Discussions similaires

  1. Réponses: 2
    Dernier message: 23/12/2013, 15h31
  2. Classe à l'intérieur d'une méthode
    Par logiciel_const dans le forum Débuter avec Java
    Réponses: 5
    Dernier message: 29/12/2010, 12h35
  3. Réponses: 5
    Dernier message: 15/05/2007, 20h51
  4. Réponses: 6
    Dernier message: 03/03/2004, 14h31
  5. une méthode qui écrit dans la sortie html ?
    Par iubito dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 03/12/2003, 15h34

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