2009-11-03 18 views
13

que estoy buscando en algún código heredado que tiene la siguiente expresión idiomática:sincronizados y locales copias de las variables

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

La advertencia que recibo de inspecciones de código de Intelli-J es:

Synchronization on local variable 'myMap' 

Es esta es la sincronización adecuada y por qué?

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

Respuesta

12

La razón por la que esto se señala como un problema es porque la sincronización en variables locales suele ser una mala idea.

Si el objeto devuelto por someGlobalInstance.getMap() es siempre el mismo, entonces el bloque sincronizado de hecho utilizar el Monitor de que los objetos cuasi-global y el código produce el resultado esperado.

También estoy de acuerdo con la sugerencia de utilizar un contenedor sincronizado, si solo necesita sincronizar las llamadas get()/put() y no tiene bloques sincronizados más grandes. Pero asegúrese de que el mapa esté solo accedido a través del contenedor o tendrá otra oportunidad para errores.

También tenga en cuenta que si someGlobalInstance.getMap() hace no devuelven el mismo objeto todo el tiempo, entonces incluso el segundo ejemplo de código no funcionará correctamente, incluso podría ser peor que el código original ya que es posible sincronizar en un objeto diferente de al que llamas get() en.

+0

Tengo una pregunta de seguimiento basada en el primer párrafo de su respuesta. ¿Puedes explicar un poco por qué la sincronización en variables locales suele ser una mala idea? ¿Es una mala idea cuando instanciamos los campos dentro del método? – Geek

+0

@ Geek: el punto de la sincronización es que utilizas un objeto que se comparte con otros hilos (de lo contrario no hace nada). Si usa una variable local como referencia, este puede o no ser el caso. –

4

Creo que el código podría estar en buen estado, dependiendo de lo que hace el método getMap(). Si mantiene una referencia a una instancia que debe compartirse entre hilos, tiene sentido. La advertencia es irrelevante ya que la variable local no se inicializa localmente.

2

Alex tiene razón en que agregar un contenedor sincronizado llamando al Collections.synchronizedMap(Map) es un enfoque típico aquí. Sin embargo, si toma este enfoque, puede haber situaciones en las que necesite sincronizarse en el bloqueo Map; p.ej. al iterar sobre el mapa.

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 
    } 
} 

En su ejemplo, la advertencia de la idea puede ser ignorado, ya que es evidente que su variable local: map se recupera desde otro lugar (someGlobalInstance) en lugar de crearse dentro del método, y por consiguiente puede acceder potencialmente de otros hilos.

Cuestiones relacionadas