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

Collection et Stream Java Discussion :

Pourquoi utiliser une Collections.synchronizedMap


Sujet :

Collection et Stream Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 938
    Par défaut Pourquoi utiliser une Collections.synchronizedMap
    Bonjour,
    Je dois créer une classe simulant un cache , pour gérer une hashMap qui contiendra les listes clé=>valeurs venant d'une base, le but c'est de n'acceder à la base qu'une seule fois pour un doublon clé=>valeur.
    voila la déclaration de ma map :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private Map<String, HashMap<String, String>> tabs = (HashMap<String, HashMap<String, String>>) Collections.synchronizedMap( new HashMap<String, HashMap<String, String>>());
    Alors ma question c'est de savoir l'intérêt d'une collection synchronisée, quel risque courir si on ne le fait pas.
    merci

  2. #2
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Salut,


    Citation Envoyé par DevServlet Voir le message
    Alors ma question c'est de savoir l'intérêt d'une collection synchronisée, quel risque courir si on ne le fait pas.
    Les collections synchronisées peuvent être manipulé depuis différents threads sans problème, et sans gérer toi-même la synchronisation. Il n'y a que pour le parcours via Iterator que tu dois faire ta propre synchronisation...

    Si tu accèdes à une collection non-synchronisé depuis différents threads, tu risques d'obtenir toutes sortes de problèmes aléatoire et difficile à mettre en évidence...


    a++

  3. #3
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 938
    Par défaut Besoin de conseils pour choix technique
    Merci pour la réponse, pendant qu'on y est j'en profite pour poser une question de conception.
    En fait j'ai une grosse table dans ma base, qui ne doit normalement pas bcp être modifiée, mon hashMap de tout à l'heure est censée contenir les informations recupérees une seule fois de la base et disponibles pour toute l'application (une sorte de classe cache).
    J'ai donc fait un singleton en synchronisant ma methode d'accès à l'instance unique, ce qui me garantit que mon hashmap ne pourra pas être utilisée par 2 Thread au même moment. voila la déclaration de ma classe :
    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
     
    public Cache extends AbstractInformation{
    	private Map<String, HashMap<String, String>> tabGlobal;
        private static Cache instanceUnique=null;
        private boolean isCacheValid=true;
     
     
     
     
    public Cache()
    {
    	tabGlobal = (HashMap<String, HashMap<String, String>>) Collections.synchronizedMap( new HashMap<String, HashMap<String, String>>());
    }
     
    public static synchronized Cache getInstance(){
        if(instanceUnique==null){
        	instanceUnique = new Cache();
        }
        return instanceUnique;
    }
     
    public void method1()
    {
    }
    ...
    j'ai quelques questions donc à ce sujet:
    Vu que j'ai jamais mis en place ce type de mécanisme:
    - je veux savoir s'il y'a des risques de dysfonctionnement ou de pertes de performances, si oui que me proposez vous pour mettre en place ce cache?
    -J'ai egalement envie de donner une durée de vie paramétrable à ce cache, un temps au bout duquel je reinitialiserai mon cache, je pense le faire avec le Timer qui après le temps parametré mettra simplement null à ma hashMap
    -Vu que la méthode d'accès à l'instance unique est dejà synchronisée, je suppose que toutes les méthodes du singleton n'ont plus à l'être. non?
    Désolé pour la longueur du post, je veux juste m'assurer que je sois pas sur le mauvais chemin.
    Merci d'avance.

  4. #4
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par DevServlet Voir le message
    J'ai donc fait un singleton en synchronisant ma methode d'accès à l'instance unique, ce qui me garantit que mon hashmap ne pourra pas être utilisée par 2 Thread au même moment.
    Faux : cela indique seulement que le code de la méthode d'accès est synchronisé !
    La synchronisation de ta Map est faite par Collections.synchronizedMap()...


    Citation Envoyé par DevServlet Voir le message
    - je veux savoir s'il y'a des risques de dysfonctionnement ou de pertes de performances, si oui que me proposez vous pour mettre en place ce cache?
    Il y a très peu de code donc ce n'est pas évident...
    Par contre la synchronisation sur getInstance() peut être un peu lourde alors qu'ion peut l'éviter (voir plus bas).

    Citation Envoyé par DevServlet Voir le message
    -J'ai egalement envie de donner une durée de vie paramétrable à ce cache, un temps au bout duquel je reinitialiserai mon cache, je pense le faire avec le Timer qui après le temps parametré mettra simplement null à ma hashMap
    -Vu que la méthode d'accès à l'instance unique est dejà synchronisée, je suppose que toutes les méthodes du singleton n'ont plus à l'être. non?
    Cela dépend complètement de tes méthodes... mais dans tout les cas tu devras prendre en compte les problèmes de synchronisation.

    Tu utilises une seule instance dans plusieurs threads, et donc tu peux potentiellement rencontrer des problèmes.

    Pour cela tu as plusieurs moyens qui va de la synchronisation (le plus "simple" mais le plus lourd) à l'algorithme de ta méthode (on peut éviter certains problèmes assez facilement sans tout synchronisé).


    En gros dans une méthode dès lors que tu manipules un attribut d'instance ou un attribut static, il y a des risques de "conflit" qu'il faut prendre en compte. Dans ce cas soit ces objets sont déjà thread-safe, soit tu dois le gérer toi même (par exemple en synchronisant ou en utilisant un copie de protection).




    Quand à ton singleton, il serait préférable de partir sur quelque chose comme cela (voir les commentaires pour plus de détail) :
    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
     
    // La classe est déclaré final : elle ne doit pas être redéfinie :
    public final Cache extends AbstractInformation{
    	// L'instance unique est crée une seule fois, grace au Classloader qui initialise la classe :
    	private static Cache INSTANCE = new Cache();
     
    	private Map<String, Map<String, String>> tabGlobal;
    	private boolean isCacheValid=true;
     
    	// Le constructeur est déclaré private : il ne doit pas être utilisé directement
    	private Cache() {
    		// Pourquoi typé si fortement, et pourquoi ce cast !?
    		tabGlobal = Collections.synchronizedMap( new HashMap<String, Map<String, String>>()) ;
    	}
     
    	// Plus besoin de synchronisation ici (on n'a plus qu'une simple affectation de référence)
    	public static Cache getInstance(){
    		return INSTANCE;
    	}
    a++

  5. #5
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    2 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 938
    Par défaut
    Merci de ta réponse, mais ça me permet de reposer d'autres questions.Tout d'abord voila ma classe complète :
    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
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
     
    public class Cache extends AbstractInformation{
    	private Map<String, HashMap<String, String>> tabGlobal;
        private static Cache instanceUnique=null;
        private boolean isCacheValid=true;
        public ArrayList<String> listCdTables;
     
     
     
    public Cache()
    {
    	tabGlobal= (HashMap<String, HashMap<String, String>>) Collections.synchronizedMap( new HashMap<String, HashMap<String, String>>());
    }
     
    public static synchronized Cache getInstance(){
        if(instanceUnique==null){
        	instanceUnique = new Cache();
        }
        return instanceUnique;
    }
     
     
    /**
     * Récupère le cdTable et le libelle selectionné par l'utilisateur et lui renvoit le cdKey pour requete sur la base
     * @param cdTable : permet de se positionner sur la bonne table
     * @param lbSel : libelle de la table dont l'Id est recherché
     * @return : cdKey recherché
     */
    public String recupIdByCdTableAndLbSel(String cdTable,String lbSel)
    {	
    	this.updateHashMap(cdTable);
    	HashMap<String, String> hashCdKeyLb=tabGlobal.get(cdTable);
    	for (Iterator i = hashCdKeyLb.keySet().iterator(); i.hasNext();) {
    		String cdKey = (String) i.next();
    		String value = (String) hashCdKeyLb.get(cdKey);
    		if(lbSel.equals(value)){return cdKey;}
    	}
    	return "";
    }
     
    	public boolean isCacheValid() {
    		return isCacheValid;
    	}
     
    	public void setCacheValid(boolean isCacheValid) {
    		this.isCacheValid = isCacheValid;
    	}
     
    	public void reinitCache()
    	{    
    		instanceUnique=null;
    	}
    	/**
             * Met à jour la hashMap si elle ne contient pas encore le cdTable
             * @param cdTable
             */
    	public void updateHashMap(String cdTable)
    	{
    	  if (!tabGlobal.containsKey(cdTable))
    	  {	  HashMap<String, String> listeCdKeyCol1=new HashMap<String, String>();
    		  String cdKey;
    		  String col1;
    		  try {
    				String[] tabParams={cdTable+"%"};
    				Collection<Object[]> colsCleValeurs=getGenericFacade().recupNColEntityGenerique("reqRecupCleValeurGlob", tabParams, "loadCdKeyLbByCdTable", "recupere les doublons clés=>valeurs");
    				for(Object[] entry:colsCleValeurs){
    					cdKey=(String)entry[0];
    					col1=(String)entry[1];
    					listeCdKeyCol1.put(col1, cdKey);
    				}
    				this.tabGlobal.put(cdTable, listeCdKeyCol1);
    			}catch (NoResultException e) {
    				log.debug(getClassName(), "loadCdKeyLbByCdTable", "pas de donnees dispo pour les cles :");
    			}
     
    	  }
    	}
     
    	/**
             * Retourne une collection de col1 correspondant à un cdTable
             * @param cdTable
             * @return
             */
    	public List<String> recupListeCol1(String cdTable)
    	{
    		this.updateHashMap(cdTable);
    		return new ArrayList<String>(tabGlobal.get(cdTable).keySet());
    	}
     
    	/**
             * Retourne une collection de col1 correspondant à un cdTable
             * @param cdTable
             * @return
             */
    	public List<String> recupListeCdKey(String cdTable)
    	{
    		this.updateHashMap(cdTable);
    		return new ArrayList<String>(tabGlobal.get(cdTable).values());
    	}
     
    	/**
             * Mets à jour la map si modif dans la base d'une cdTable
             * @param cdTable
             */
    	public void updateOneTableByCdTable(String cdTable)
    	{
    		if (tabGlobal.containsKey(cdTable))
    		{
    			tabGlobal.remove(cdTable);
    		}
    		this.updateHashMap(cdTable);
    	}
     
    	/**
             * Vide le cache
             */
    	public void clearCache()
    	{
    		this.loadListCdKeys();
    		for (String cdTable: listCdTables)
    		{
    			tabGlobal.get(cdTable).clear();
    		}
    		this.tabGlobal.clear();
    	}
     
     
    }
    Comme tu pourras les constater dans ce singleton tu trouveras des methodes de suppresion/ajout de ma map, et aussi des methodes de récupération de valeurs via cette map. Avec ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // Plus besoin de synchronisation ici (on n'a plus qu'une simple affectation de référence)
    	public static Cache getInstance(){
    		return INSTANCE;
    	}
    Qu'est ce qui me garantit que pendant qu'un Thread sera entrain de supprimer une entrée, l'autre Thread n'ajoutera pas la même entrée parallelement?
    Dans ce bout de code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public static synchronized Cache getInstance(){
        if(instanceUnique==null){
        	instanceUnique = new Cache();
        }
        return instanceUnique;
    }
    Je me disais que j'avais la garantie qu'à un instant t qcq 2 Thread ne pouvaient pas accéder simultanement à aucune des methodes.c'est le principe du patron de conception Singleton , non ?
    Puis je avoir plus d'explication de cette phrase ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    En gros dans une méthode dès lors que tu manipules un attribut d'instance ou un attribut static, il y a des risques de "conflit" qu'il faut prendre en compte. Dans ce cas soit ces objets sont déjà thread-safe, soit tu dois le gérer toi même (par exemple en synchronisant ou en utilisant un copie de protection).
    Au vu de ma classe puis je avoir une suggestion à cette question ?:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    -J'ai egalement envie de donner une durée de vie paramétrable à ce cache, un temps au bout duquel je reinitialiserai mon cache, je pense le faire avec le Timer qui après le temps parametré mettra simplement null à ma hashMap
    -Vu que la méthode d'accès à l'instance unique est dejà synchronisée, je suppose que toutes les méthodes du singleton n'ont plus à l'être. non?
    Merci d'avance

  6. #6
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par DevServlet Voir le message
    Je me disais que j'avais la garantie qu'à un instant t qcq 2 Thread ne pouvaient pas accéder simultanement à aucune des methodes.c'est le principe du patron de conception Singleton , non ?
    Non : le principe du Singleton est de proposer une seule et unique instance d'une classe, et ce pour toute l'application. Par contre les méthodes doivent être thread-safe si on les utilise depuis différents threads.

    Note bien que je fait la distinction entre thread-safe et synchronisé :
    • "thread-safe" signifie que le code est sûr même en cas d'utilisation simultané depuis différents threads.
    • La synchronisation permet de s'assurer qu'il n'y aura qu'un seul et unique thread qui exécutera un code à un moment donné. C'est un manière de faire du code thread-safe parmis d'autres...



    Dans ton cas la méthode getInstance() est synchronisé. Cela signifie UNIQUEMENT que son code ne pourra être exécuté que par un thread à la fois. Cela permet donc dans ton cas de t'assurer que l'instance unique ne sera créé qu'une seule fois... Sans synchronisation on pourrait très bien tomber dans le cas où 2 threads entre en même temps dans la méthode dans le if...

    Dans mon cas la méthode n'est pas synchronisé mais ne pose aucun problème : l'instance unique est créé au chargement de la classe par le classloader. Ensuite il s'agit d'une copie de référence qui ne nécessite pas de synchronisation...



    Par contre tout ceci n'a aucun impact sur les autres méthodes de la classe, qui devront être elle-aussi thread-safe d'une manière ou d'une autre...




    Citation Envoyé par DevServlet Voir le message
    Puis je avoir plus d'explication de cette phrase ?
    Cela signifie que lorsqu'une méthode manipule un attribut d'instance ou static, il y a des risques de problèmes dans un contexte multi-thread et il faut donc prendre cela en compte.

    Si elle se contente d'utiliser ses paramètres ou ses variables locales il n'y a aucun problème de ce genre...



    Citation Envoyé par DevServlet Voir le message
    -J'ai egalement envie de donner une durée de vie paramétrable à ce cache, un temps au bout duquel je reinitialiserai mon cache, je pense le faire avec le Timer qui après le temps parametré mettra simplement null à ma hashMap
    Oui et quel est la question ?

    Citation Envoyé par DevServlet Voir le message
    -Vu que la méthode d'accès à l'instance unique est dejà synchronisée, je suppose que toutes les méthodes du singleton n'ont plus à l'être. non?
    Non !
    Comme je l'ai dit le fait de synchronisé getInstance() ne permet pas de synchronisé toutes les méthodes de la classe...


    Bref pour chaque méthode il faut bien penser aux différents cas possible. Tout synchroniser est la solution la plus simple à mettre en place, mais également la plus couteuse en temps d'exécution...


    a++

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

Discussions similaires

  1. Utiliser une collection dans plusieurs Userform
    Par citro dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 07/08/2014, 08h19
  2. créer et utiliser une collection probleme
    Par clem62173 dans le forum VB.NET
    Réponses: 5
    Dernier message: 28/04/2010, 09h41
  3. Script utilisant une collection
    Par rodgeur37 dans le forum PL/SQL
    Réponses: 6
    Dernier message: 22/09/2009, 16h46
  4. [CR] Utiliser une collection comme source de données
    Par augereau dans le forum SAP Crystal Reports
    Réponses: 1
    Dernier message: 03/11/2006, 16h40
  5. [C#]Pourquoi utiliser une structure plutôt qu'une classe?
    Par egoom dans le forum Windows Forms
    Réponses: 2
    Dernier message: 30/10/2006, 09h49

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