La proprietà statale copre tutto ciò che una classe deve essere infallibile

0

Come menzionato da Java_author ,

When defining which variables form an object's state, we want to consider only the data that object owns....

In many case, ownership and encapsulation go together— the object encapsulates the state it owns and owns the state it encapsulates....

A class usually does not own the objects passed to its methods or constructors, unless the method is designed to explicitly transfer ownership of objects passed in (such as the synchronized collection wrapper factory methods)...

Per garantire la sicurezza del thread, una classe non thread-safe deve tracciare una linea sulle variabili di stato che possiede per garantire la sicurezza del thread. Quelle variabili di stato possono essere popolate in classe attraverso la generalizzazione, l'associazione, l'iniezione di dipendenza e cosa no.

A mio parere, l'autore di Java ha già dato (sopra) un parametro per valutare la proprietà dello stato per la sicurezza dei thread, l'oggetto incapsula lo stato che possiede e possiede lo stato che incapsula

Modifica dopo questo commento :

Sotto codice preso dal Listato 4.4 / 4.5 da Java_author , guarda la classe MonitorVehicleTracker al di sotto di possedere locations che viene popolata attraverso il costruttore di copie,

package responsive;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

class MutablePoint{
    public int x, y;

    public MutablePoint() {
        x=0; y=0;
    }

    public MutablePoint(MutablePoint p) {
        this.x = p.x;
        this.y = p.y;
    }
}

public class MonitorVehicleTracker {

    private final Map<String, MutablePoint> locations;

    public MonitorVehicleTracker( // Copy constructor
                        Map<String,MutablePoint> locations) {
        this.locations = deepCopy(locations);

    }

    public synchronized Map<String, MutablePoint> getLocations(){
        return deepCopy(locations);
    }

    public synchronized MutablePoint getLocation(String id) {

        MutablePoint loc = locations.get(id);
        return loc == null ? null : new MutablePoint(loc);
    }

    public synchronized void setLocation(String id, int x, int y) {
        MutablePoint loc = locations.get(id);
        if(loc == null) {
            throw new IllegalArgumentException("No such id: " + id);
        }
        loc.x = x;
        loc.y = y;
    }


    private static Map<String, MutablePoint> deepCopy(
            Map<String, MutablePoint> m){

        Map<String, MutablePoint> result = 
                    new HashMap<String, MutablePoint>();

        for(String id: m.keySet()) {
            result.put(id, new MutablePoint(m.get(id)));
        }

        return Collections.unmodifiableMap(result);
    }


}

utilizzato dal thread della GUI,

Map<String, Point> location = vehicles.getLocations();
for(String key: locations.keySet()){
   renderVehicle(key, locations.get)key));
}

e usato dal thread di aggiornamento,

void vehicleMoved(VehicleMovedEvt evt){
   Point loc = evt.getNewLocation();
   vehicles.setLocations(evt.getVehicleId(), loc.x, loc.y);
}

Per una classe non thread-safe per rendere thread-safe,

Sei d'accordo con questo parametro per applicare criterio di sincronizzazione solo sulle variabili di stato che possiedi per garantire la sicurezza dei thread?

    
posta user1787812 09.10.2017 - 22:09
fonte

2 risposte

2

Non confondere eccessivamente la proprietà con la sicurezza del thread. Per rendere una classe protetta da un codice, devi renderla sicura. Non piu. Non di meno. Questo significa:

  • Non puoi avere due thread scrivere sugli stessi dati contemporaneamente
  • Non è possibile avere una scrittura di thread sui dati e una sola lettura da essa allo stesso tempo.
  • La sincronizzazione che aggiungi alla classe non viola nessuno degli invarianti dei suoi metodi (come qualsiasi garanzia di determinismo).

Ora capita che l'incapsulamento e la proprietà attirino le linee dure nella sabbia, e può essere più facile implementare la suddetta sicurezza se si sfruttano queste linee esistenti. Ad esempio, uno dei problemi nella realizzazione del codice multithread è deadlock, in cui due thread si contendono due lock in un modo che impedisce di fare progressi. Se metti la tua sincronizzazione ai margini dei dati incapsulati, diventa facile dimostrare che una determinata classe è senza deadlock.

Ma la proprietà non può coprire tutto. Considera che la proprietà significa che puoi fare tutto ciò che vuoi con i dati. Leggetelo, scrivetelo, salvatene copie temporanee. È tuo. In molte situazioni multithreading, vuoi che molti thread siano in grado di leggere i dati simultaneamente. Per fare ciò, il "proprietario" deve rinunciare al diritto di scrivere su quei dati fino al completamento delle letture. In generale, il nostro concetto di "proprietà" non è abbastanza sottile da attingere a distinzioni del genere.

    
risposta data 10.10.2017 - 20:54
fonte
0

Sì, gli oggetti formati tramite composizione possiedono gli oggetti dati di cui sono composti generalmente. Questo di per sé non garantisce la sicurezza del filo, però. Ci sono alcuni motivi:

  1. Lo stesso oggetto può essere chiamato su più thread, quindi potrebbe effettivamente rendere il proprio stato incoerente se non si prendono le dovute precauzioni (come usare un mutex o un costrutto simile)
  2. Se l'oggetto A possiede l'oggetto B, ma l'oggetto C richiede un riferimento anziché una copia dell'oggetto B, quindi entrambi A & C potrebbe essere in grado di modificare l'oggetto B se non stai attento.

Chiedi anche:

For code:

class MyClass { 
    private HashSet<Person> mySet = new HashSet<Person>(); 
    private int x;
}

Does object's state ownership involve just x, and mySet or state ownership involves x, mySet and Person? Here, MyClass has composition relationship with HashSet.

Direi che MyClass possiede mySet e x e che mySet possiede ogni Person che contiene. (Quindi anche MyClass in modo transitivo possiede ogni Person .) Questo è tutto presupponendo che nessun altro abbia forti riferimenti a questi oggetti. (E in generale solo un oggetto dovrebbe mai avere un riferimento strong a un dato oggetto.)

    
risposta data 10.10.2017 - 05:07
fonte