2015-11-04 7 views
5

A pagina 65 e 66 di Java Concurrency in Practice Brian Goetz elenca il seguente codice:In che modo DelegatingVehicleTracker (p. 65 Goetz) restituisce una visualizzazione "live"?

@ThreadSafe 
public class DelegatingVehicleTracker { 
private final ConcurrentMap<String, Point> locations; 
private final Map<String, Point> unmodifiableMap; 

public DelegatingVehicleTracker(Map<String, Point> points) { 
    locations = new ConcurrentHashMap<String, Point>(points); 
    unmodifiableMap = Collections.unmodifiableMap(locations); 
} 

public Map<String, Point> getLocations() { 
    return unmodifiableMap; 
} 

public Point getLocation(String id) { 
    return locations.get(id); 
} 

public void setLocation(String id, int x, int y) { 
    if (locations.replace(id, new Point(x, y)) == null) 
     throw new IllegalArgumentException("invalid vehicle name: " + id); 
} 

// Alternate version of getLocations (Listing 4.8) 
public Map<String, Point> getLocationsAsStatic() { 
    return Collections.unmodifiableMap(
      new HashMap<String, Point>(locations)); 
} 
} 

A proposito di questa classe Goetz scrive:

" ... la versione delegante [il codice di cui sopra] restituisce una vista "live" non modificabile ma "live" dei luoghi del veicolo Ciò significa che se il thread A chiama getLocations() e il thread B modifica in seguito la posizione di alcuni dei punti , tali modifiche si riflettono nella mappa restituita al thread A ".

In che senso la "Modifica" di Thread A non può essere "live"? Non vedo come le modifiche apportate da Thread B tramite chiamate a setLocation() si riflettano nellaMod non modificabile di Thread A. Questo sembra il caso solo se il thread A ha costruito una nuova istanza di DelegatingVehicleTracker. Ma il thread A contiene un riferimento a questa classe, non vedo come ciò sia possibile.

Goetz prosegue dicendo che getLocationsAsStatic() potrebbe essere definito come una "immutabile visione della flotta richiesta". Sono confuso. Mi sembra che proprio l'opposto sia il caso, che una chiamata a getLocationsAsStatic() restituisca effettivamente la vista "live" e una chiamata a getLocations(), se la classe non sia stata costruita di nuovo, restituisca la vista statica e invariata della flotta di macchine.

Cosa mi manca qui in questo esempio?

Tutti i pensieri o le prospettive sono apprezzati!

risposta

3

Penso che la tua confusione sia dovuta a incomprensioni di Collections.unmodifiableMap. La mutazione diretta della mappa restituita da Collections.unmodifiableMap non è consentita, tuttavia la mutazione della mappa di supporto è completamente soddisfacente (a condizione che la mappa di supporto consenta la mutazione).Per esempio:

Map<String,String> map = new HashMap<>(); 
Map<String, String> unmodifiableMap = Collections.unmodifiableMap(map); 

map.put("key","value"); 

for (String key : unmodifiableMap.keySet()) { 
    System.out.println(key); // prints key 
} 

Così, unmodifiableMap nell'esempio DelegatingVehicleTracker è sostenuta da una mappa mutabile locations (un thread-safe uno). setLocation muta atomicamente e quindi le modifiche saranno visibili per i thread contenenti riferimenti allo unmodifiableMap sapendo che quei thread non possono mutare il unmodifiableMap. I lettori non hanno accesso a locations, quindi la modifica verrà eseguita solo tramite DelegatingVehicleTracker e quindi con il nome delegation.

+0

Grazie Sleiman, e altri; ora capisco. Spiegherò a me stesso (di usare sperabilmente agli altri): DelegatingVehicleTracker può modificare, ma le classi client non possono. Una chiamata a unmodifiableMap nel tuo codice di esempio sopra genererebbe un'eccezione (l'ho provata), ma, ovviamente, l'insert to map non lo fa. UnmodifiableMap è come uno spettacolo di marionette visto attraverso uno schermo di vetro che impedisce al pubblico di intromettersi. –

+0

@BenWeaver c'è un termine per la metafora che hai appena descritto, è la delega –

+0

Grazie, Sleiman! –

1

In che senso la "Modifica" non può essere "live" di Thread A? Io non vedo come le modifiche apportate da Discussione B tramite chiamate a setLocation() sarebbero riflesse in filo di un'unmodifiableMap

Questo perché getLocations() restituisce una mappa immodificabile avvolto della mappa mutabile vero e proprio.

Quindi qualsiasi modifica successiva verrà automaticamente riflessa nella mappa restituita originale poiché entrambi puntano infine allo stesso oggetto Mappa interno.

Goetz continua a dire che getLocationsAsStatic() potrebbe essere chiamato fosse una "visione immutabile della flotta necessaria"

Questo codice

public Map<String, Point> getLocationsAsStatic() { 
return Collections.unmodifiableMap(
     new HashMap<String, Point>(locations)); 
} 

è statica, nel senso che il futuro le modifiche a locations non vengono riflesse poiché restituisce una nuova mappa con una copia di tutte le coppie chiave-valore correnti.

0

getLocations() restituirà un sola lettura mappa che rispecchierà gli aggiornamenti dopogetLocations() si chiama.

getLocationsAsStatic() d'altra parte, restituirà un di sola lettura-snapshot (aka copia completa) della mappa posizione al momento getLocationsAsStatic() si chiama.

Facciamo un esempio:

Map<String, Point> locs  = // a map with point A(1,1) in it 
DelegatingVehicleTracker tracker = DelegatingVehicleTracker(locs); 

Map<String, Point> snapshot = getLocationsAsStatic(); 
Map<String, Point> live  = getLocations(); 

Point newB = // a point A(2,2) 
tracker.setLocation(newB); 

snapshot.get("A"); // will read A(1,1) 
live.get("A");  // will read A(2,2) 
+0

questa è in realtà la domanda, è ciò che l'OP non capisce –

Problemi correlati