2011-02-09 6 views
0

J'ai une implémentation de cache comme ceci:Synchronisation des structures imbriquées de données entre threads en Java

class X 
{ 
    private final Map<String, ConcurrentMap<String, String>> structure = new HashMap...(); 

    public String getValue(String context, String id) 
    { 
    // just assume for this example that there will be always an innner map 
    final ConcurrentMap<String, String> innerStructure = structure.get(context); 

    String value = innerStructure.get(id); 
    if(value == null) 
    { 
     synchronized(structure) 
     { 
      // can I be sure, that this inner map will represent the last updated 
      // state from any thread? 
      value = innerStructure.get(id); 
      if(value == null) 
      { 
      value = getValueFromSomeSlowSource(id); 
      innerStructure.put(id, value); 
      } 
     } 
    }  
    return value; 
    } 
} 

Est-ce thread-safe mise en œuvre? Puis-je être sûr d'obtenir le dernier état mis à jour de n'importe quel thread à l'intérieur du bloc synchronisé? Est-ce que ce changement de comportement si j'utilise un java.util.concurrent.ReentrantLock au lieu d'un bloc synchronisé, comme ceci:

... 
if(lock.tryLock(3, SECONDS)) 
{ 
    try 
    { 
    value = innerStructure.get(id); 
    if(value == null) 
    { 
     value = getValueFromSomeSlowSource(id); 
     innerStructure.put(id, value); 
    } 
    } 
    finally 
    { 
    lock.unlock(); 
    } 
} 
... 

Je sais que les membres de dernière instance sont synchronisées entre les threads, mais est-ce vrai aussi pour les objets tenu par ces membres?

Peut-être que c'est une question stupide, mais je ne sais pas comment le tester pour être sûr que cela fonctionne sur tous les OS et toutes les architectures.

Répondre

1

Pour commencer, ce n'est pas une question stupide. La synchronisation est vraiment difficile à obtenir, et je ne prétends pas être un expert en la matière.

Dans votre programme, au contexte indiqué, oui, vous pouvez supposer que le String que vous obtenez est la version la plus récente. Cependant, votre code n'est toujours pas sûr car vous lisez une valeur à partir du Map en dehors du bloc synchronized. Si cette lecture se produit en même temps que le Map est inséré dans une valeur, vous n'êtes pas garanti de récupérer une valeur sensible. Je sais que sur certaines implémentations au moins, cela peut provoquer une boucle infinie en raison d'une certaine étrangeté dans l'implémentation. La version courte est que vous ne devriez pas avoir une structure qui est lue ou écrite par plusieurs threads à moins que vous ne la gardiez avec une primitive de synchronisation comme synchronized ou un verrou, ou à moins que cette structure soit spécifiquement conçue pour être verrouillée. libre comme le ConcurrentHashMap. Dans ce cas, vous pouvez utiliser le code ReentrantLock pour protéger l'accès à la structure et faire une attente temporisée, mais si vous le faites, vous devez garantir que toutes les lectures de la structure sont également protégées par le même verrou. Sinon, vous risquez plusieurs threads de voir des données incohérentes ou corrompues.

+0

Merci pour votre allusion à la lecture non synchronisée, je vais mettre à jour ma question en conséquence. – Dominik

0

Vous pourriez avoir besoin d'utiliser ConcurrentHashMap pour hashmap extérieur et InnerHashMap pour se synchroniser et de mettre les opérations au niveau du godet

1

Dans le cas de la mise en œuvre classe X, une valeur de innerStructure peut être mis à jour lorsque la valeur est non nulle . Donc, il est supposé que toute la valeur de innerStructure n'est pas nulle. Dans cette hypothèse, si la structure et la innerStructure ne sont pas mises à jour sans getValue(), ceci est sûr pour les threads.

Si la structure et la innerStructure sont mises à jour à une autre fonction, la valeur que renvoie getValue a la possibilité de ne pas le devenir dans la dernière valeur.

Bien qu'il semble que l'amélioration de la performance est un but, le problème et la solution de contournement sont décrits sur le site suivant.

http://www.ibm.com/developerworks/java/library/j-jtp03304/

(Est-ce que résoudre le problème de verrouillage revérifié)

+0

Merci pour votre avis et le lien – Dominik

Questions connexes