Se più di un thread può accedere a un campo dovrebbe essere contrassegnato come volatile?

StackOverflow https://stackoverflow.com/questions/1621495

  •  06-07-2019
  •  | 
  •  

Domanda

Lettura di alcuni thread ( problemi di concorrenza comuni , parola chiave volatile , modello di memoria ) Sono confuso sui problemi di concorrenza in Java.

Ho molti campi a cui accede più di un thread. Devo esaminarli e contrassegnarli come volatili?

Quando costruisco una classe non sono a conoscenza del fatto che più thread accedano ad essa, quindi sicuramente non è sicuro lasciare che qualsiasi campo non sia volatile, quindi a quanto ho capito ci sono pochissimi casi che non usarlo. È corretto?

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

È stato utile?

Soluzione

Se si accede a un campo da più thread, dovrebbe essere 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. La semplice marcatura dei campi volatile o finale non è sufficiente per la sicurezza della filettatura. Esistono problemi di coerenza (atomicità delle modifiche a più campi), preoccupazioni sulla segnalazione inter-thread (ad esempio utilizzando wait e notifica ), ecc.

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

Invece, il software dovrebbe essere progettato in modo che i thread simultanei interagiscano l'uno con l'altro il meno possibile, preferibilmente per niente. I punti in cui interagiscono devono essere chiaramente identificati in modo da poter progettare i controlli di concorrenza adeguati.

Altri suggerimenti

Bene, hai letto quelle altre domande e presumo che tu abbia già letto le risposte, quindi evidenzierò solo alcuni punti chiave:

  1. cambieranno? in caso contrario, non è necessario volatile
  2. se sì, allora il valore di un campo è correlato a un altro? se sì, vai al punto 4
  3. quanti thread lo cambieranno? se solo 1, allora volatile è tutto ciò di cui hai bisogno
  4. se la risposta al numero 2 è " no " o più di un thread ci scriverà, quindi la sola volatile non è non abbastanza , probabilmente dovrai sincronizzare l'accesso

Aggiunto:
Se il campo fa riferimento a un oggetto, avrà campi propri e tutte queste considerazioni si applicano anche a questi campi.

Se devi chiedere, usa i lucchetti. volatile può essere utile in alcuni casi, ma è molto, molto difficile da ottenere. Ad esempio:

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

Se due thread eseguono Increment () contemporaneamente, è possibile che il risultato sia counter = 1 . Questo perché il computer prima recupererà counter , ne aggiungerà uno e lo salverà nuovamente. Volatile forza solo il salvataggio e il caricamento in un ordine specifico rispetto ad altre istruzioni.

Nota che sincronizzato di solito ovvia alla necessità di volatile - se tutti gli accessi a un determinato campo sono protetti dallo stesso monitor, volatile mai necessario.

L'uso di volatile per creare algoritmi senza blocco è molto, molto difficile; attenersi a sincronizzato a meno che non si disponga di prove concrete che sia già troppo lento e di aver effettuato un'analisi dettagliata dell'algoritmo che si intende implementare.

La risposta breve è no. I problemi di threading richiedono più pensiero e pianificazione di questo. Vedi questo per alcune limitazioni su quando volatile aiuta per threading e quando no. 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 desideri cambiarla se soddisfa un criterio. La lettura dall'array e la scrittura nell'array sono istruzioni diverse e devono essere sincronizzate insieme. Volatile non è abbastanza.

Considera anche il caso in cui la variabile fa riferimento a un oggetto mutabile (diciamo un array o una Collezione), quindi interagire con quell'oggetto non sarà sicuro per il thread solo perché il riferimento è volatile.

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