2009-10-25 3 views
6

Lettura di alcuni thread (common concurrency problems, volatile keyword, memory model) Sono confuso sui problemi di concorrenza in Java.Se più thread possono accedere a un campo devono essere contrassegnati come volatili?

Ho molti campi a cui si accede da più di un thread. Devo passare attraverso di loro e contrassegnarli tutti come volatili?

Quando si costruisce una classe che non sono a conoscenza di se più thread saranno accedervi, quindi sicuramente non è sicuro di lasciare qualsiasi campo non essere volatile, in modo dalla mia comprensione non c'è pochissimi casi si non lo uso . È corretto?

Per me questo è specifico per le JVM versione 1.5 e successive, ma non mi sento limitato a rispondere alla mia configurazione specifica.

risposta

3

Se si accede a un campo da più thread, è necessario specificare volatile o final oppure accedere solo con blocchi sincronizzati. Altrimenti, i valori assegnati potrebbero non essere visibili ad altri thread.

Una classe deve essere progettata in modo specifico per l'accesso simultaneo da più thread. Semplicemente contrassegnare i campi volatili o finali non è sufficiente per la sicurezza del filo. Ci sono problemi di coerenza (atomicità delle modifiche a più campi), le preoccupazioni circa la segnalazione inter-thread (per esempio usando wait e notify), ecc

Quindi, è più sicuro supporre che un oggetto deve essere visibile solo a un thread singolo a meno che non sia documentato diversamente. Non è necessario rendere tutti i tuoi oggetti thread-safe, ed è costoso — in termini di velocità del software, ma soprattutto, in termini di spese di sviluppo.

Invece, il software deve essere progettato in modo che i thread simultanei interagiscano l'uno con l'altro il meno possibile, preferibilmente non del tutto. I punti in cui interagiscono devono essere chiaramente identificati in modo da poter progettare i controlli della concorrenza appropriati.

4

Beh, avete letto le altre domande e presumo che hai letto le risposte già, quindi mi limiterò a evidenziare alcuni punti chiave:

  1. stanno andando a cambiare? in caso contrario, non è necessario il volatile
  2. se sì, allora il valore di un campo è correlato a un altro? se sì, andare al punto 4
  3. quanti thread lo cambieranno? se solo 1, allora volatile è tutto ciò che serve
  4. se la risposta al numero 2 è "no" o più di un thread sta per scriverlo, quindi solo volatile è non sufficiente, probabilmente sarà necessario sincronizzare l'accesso

Aggiunto:
Se il riferimento di campo di un oggetto, allora avrà i campi della propria e di tutti coloro considerazione si applica anche a questi campi.

1

La risposta breve è no. I problemi di threading richiedono più riflessione e pianificazione di questo. Si veda this per alcune limitazioni su quando la volatilità aiuta nel threading e quando non lo fa. La modifica dei valori deve essere correttamente sincronizzata, ma in genere la modifica richiede lo stato di più di una variabile alla volta. Supponiamo ad esempio che tu abbia una variabile e tu voglia cambiarla se soddisfa un criterio. La lettura dall'array e la scrittura sull'array sono istruzioni diverse e devono essere sincronizzati insieme. Volatile non è abbastanza.

Considera anche il caso in cui la variabile fa riferimento a un oggetto mutabile (ad esempio un array o una raccolta), quindi l'interazione con quell'oggetto non sarà thread-safe solo perché il riferimento è volatile.

2

Se devi chiedere, usa le serrature. volatile può essere utile in alcuni casi, ma è molto, molto difficile avere ragione. Ad esempio:

class Foo { 
    private volatile int counter = 0; 
    int Increment() { 
    counter++; 
    return counter; 
    } 
} 

Se due thread eseguono Increment() allo stesso tempo, è possibile che il risultato sia counter = 1. Questo perché il computer prima recupererà , aggiungine uno, quindi lo salverà. Volatile costringe semplicemente il salvataggio e il caricamento a verificarsi in un ordine specifico rispetto ad altre istruzioni.

Nota che synchronized eliminerebbe la necessità di volatile - se tutti gli accessi ad un determinato campo sono protetti dallo stesso monitor, non sarà mai necessario volatile.

L'utilizzo di volatile per rendere gli algoritmi senza blocco è molto, molto difficile; attenersi a synchronized a meno che non si abbia una prova concreta del fatto che sia già troppo lento e che si siano svolte analisi dettagliate sull'algoritmo che si intende implementare.

+0

Per questo particolare caso d'uso, vedere AtomicInteger, piuttosto che utilizzare 'sincronizzato '. – erickson

+1

Infatti. Volevo solo dimostrare le insidie ​​di usare ciecamente "sincronizzati" senza capire esattamente cosa fa e cosa non fornisce – bdonlan