Domanda

sto guardando un po 'di codice legacy che ha la seguente forma:

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

L'avvertimento che ricevo da controlli di codice di Intelli-J è:

Synchronization on local variable 'myMap'

E 'questa la sincronizzazione appropriata e perché?

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

Soluzione

Il motivo di questo è contrassegnata come un problema è perché la sincronizzazione su variabili locali di solito è una cattiva idea.

Se l'oggetto restituito da someGlobalInstance.getMap() è sempre lo stesso, allora il blocco sincronizzato fa infatti usa monitor che oggetti quasi-globale e il codice produce il risultato previsto.

Sono d'accordo anche con il suggerimento di utilizzare un wrapper sincronizzato, se avete solo bisogno di sincronizzare i chiamate get() / put() e non hanno blocchi sincronizzati ogni più grande. Ma fare in modo che la mappa è solo si accede tramite l'involucro o avrete un'altra possibilità per i bug.

Si noti inoltre che se someGlobalInstance.getMap() non restituiscono lo stesso oggetto per tutto il tempo, allora anche il tuo esempio secondo codice non funziona correttamente, potrebbe anche essere peggiore di quanto il tuo codice originale dal momento che si potrebbe sincronizzare su un oggetto diverso da quello che si chiama get() on.

Altri suggerimenti

Credo che il codice potrebbe essere solido, a seconda di ciò che il metodo getMap () fa. Se si mantiene un riferimento a un'istanza che deve essere condiviso tra thread ha senso. L'avvertimento è irrilevante, poiché la variabile locale non è inizializzata a livello locale.

Credo che sarebbe meglio utilizzare sincronizzato wrapper per la vostra mappa

Alex è corretta in quanto l'aggiunta di un involucro sincronizzato chiamando Collections.synchronizedMap(Map) è un approccio tipico qui. Tuttavia, se si prende questo approccio ci può ancora essere situazioni in cui è necessario sincronizzare il blocco del Map; per esempio. quando l'iterazione sulla mappa.

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

Nel tuo esempio, l'avviso da IDEA può essere ignorato, in quanto è evidente che la variabile locale: map viene recuperato da qualche altra parte (someGlobalInstance) piuttosto che essere creato all'interno del metodo, e quindi può potenzialmente accedere da altri thread.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top