2009-11-03 2 views
13

Je suis à la recherche à un code existant qui a l'idiome suivant:copies des variables Synchronisé et locales

Map<String, Boolean> myMap = someGlobalInstance.getMap(); 
synchronized (myMap) { 
    item = myMap.get(myKey); 
} 

L'avertissement que je reçois des inspections de code de Intelli-J est:

Synchronization on local variable 'myMap' 

Est ceci la synchronisation appropriée et pourquoi?

Map<String, Boolean> myMap = someGlobalInstance.getMap(); 
synchronized (someGlobalInstance.getMap()) { 
    item = myMap.get(myKey); 
} 

Répondre

12

La raison pour laquelle cela est signalé comme étant un problème est que la synchronisation sur les variables locales est généralement une mauvaise idée.

Si l'objet retourné par someGlobalInstance.getMap() est toujours le même, le bloc synchronisé n'utilise en fait que les objets quasi-globale surveiller et le code produit le résultat attendu. Je suis également d'accord avec la suggestion d'utiliser un wrapper synchronisé, si vous avez seulement besoin de synchroniser les appels get()/put() et ne pas avoir de plus gros blocs synchronisés. Mais assurez-vous que la carte est seulement accessible via l'emballage ou vous aurez une autre chance pour les bugs.

Notez également que si someGlobalInstance.getMap() ne fait pas retourner le même objet tout le temps, alors même votre deuxième exemple de code ne fonctionne pas correctement, il pourrait même être pire que votre code d'origine puisque vous pouvez synchroniser sur un objet différent de celui que vous appelez get().

+0

J'ai une question de suivi basée sur le premier paragraphe de votre réponse. Pouvez-vous expliquer un peu pourquoi la synchronisation sur les variables locales est généralement une mauvaise idée? Est-ce une mauvaise idée lorsque nous instancions les champs à l'intérieur de la méthode? – Geek

+0

@Geek: le point sur la synchronisation est que vous utilisez un objet qui est partagé avec d'autres threads (sinon il ne fait rien). Si vous utilisez une variable locale comme référence, cela peut ou non être le cas. –

4

Je pense que le code pourrait être son, en fonction de la méthode getMap() fait. S'il garde une référence à une instance qui doit être partagée entre les threads, cela a du sens. L'avertissement n'est pas pertinent car la variable locale n'est pas initialisée localement.

2

Alex a raison de dire que l'ajout d'un wrapper synchronisé en appelant Collections.synchronizedMap(Map) est une approche typique ici. Cependant, si vous adoptez cette approche, il se peut que vous ayez besoin de synchroniser sur le verrou de Map; par exemple. en itérant sur la carte.

Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<String, String>()); 

// Synchronized on map to prevent ConcurrentModificationException whilst iterating. 
synchronized (syncMap) { 
    for (Map.Entry<String, String> entry : syncMap.entrySet()) { 
    // Do work 
    } 
} 

Dans votre exemple, l'avertissement d'IDEA peut être ignoré, car il est évident que votre variable locale: map est récupéré d'ailleurs (someGlobalInstance) plutôt que d'être créée au sein de la méthode, et peut donc être potentiellement accédée à partir d'autres discussions.

Questions connexes