Sono assegnazioni a 64 bit in atomico Java su una macchina a 32 bit?

Se ho un codice come questo –

long x; x = 0xFFFFFFFFL; 

Se eseguo questo codice su una macchina a 32 bit, è garantito che sia atomico o è ansible che una lettura di thread diversa x, possa ottenere un valore incompleto / inutile?

Ecco il breve riassunto:

  • Per i riferimenti, le letture / scritture sono SEMPRE atomiche (anche nelle implementazioni a 64 bit!)
  • Per int , char , byte , short , boolean , float , reads / writes sono SEMPRE atomici
  • Per il double e il long , se sono volatile , le letture / scritture sono SEMPRE atomiche

Quindi c’è solo un’eccezione dove le letture / scritture potrebbero non essere atomiche:

  • Per il double e il long , se NON sono dichiarati volatile , NON sono GARANTITI per essere atomici

Quindi, per quanto riguarda l’atomicità della lettura / scrittura dei dati condivisi, è necessario rendere volatile qualsiasi double o long . Tutto il resto è già garantito per essere atomico, indipendentemente dal numero di bit utilizzati nell’implementazione reale.


Sulla specifica

Ecco la sezione pertinente qui riprodotta per una rapida consultazione:

JLS 17.7 Trattamento non atomico di double e long

Alcune implementazioni potrebbero trovare conveniente dividere una singola azione di scrittura su un valore a 64 bit long o double in due azioni di scrittura su valori adiacenti a 32 bit. Per motivi di efficienza, questo comportamento è specifico per l’implementazione; Le macchine virtuali Java sono libere di eseguire scritture su valori long e double atomicamente o in due parti.

Ai fini del modello di memoria del linguaggio di programmazione Java, una singola scrittura su un valore volatile long o double non volatile long viene trattata come due scritture separate: una per ciascuna metà a 32 bit. Ciò può comportare una situazione in cui un thread vede i primi 32 bit di un valore a 64 bit da una scrittura e i secondi 32 bit da un’altra scrittura. Le scritture e le letture di valori volatile long e double sono sempre atomici. Le scritture e le letture dei riferimenti sono sempre atomiche, indipendentemente dal fatto che siano implementate come valori a 32 o 64 bit.

Gli implementatori VM sono incoraggiati ad evitare di dividere i propri valori a 64 bit laddove ansible. I programmatori sono invitati a dichiarare volatile valori condivisi a 64 bit oa sincronizzare correttamente i loro programmi per evitare possibili complicazioni.

Guarda anche

  • JLS 17.6 Word Tearing – garantisce ad es. Che un byte possa essere aggiornato senza interferenze del vicino
  • Campi volatile JLS 8.3.1.4
  • Esercitazioni su Java / Classi essenziali / Concurrency / Atomic Variables
    • Si noti che data int i; , i++ NON è atomico!

Domande correlate

  • C’è qualche punto nell’usare un volatile lungo?
  • Come dichiarare gli elementi dell’array volatile in Java?
    • Un volatile long[] è un riferimento volatile a un array di long
    • Gli stessi elementi long non sono volatile

No non lo sono. Un archivio a 64 bit viene considerato come due negozi a 32 bit separati. Quindi in un ambiente concorrente tale variabile può avere il 32 alto di una scrittura e il 32 basso di un’altra scrittura, ovviamente non thread-safe.

La Sezione 8.4 della specifica Java Virtual Machine afferma che un double o long che non è dichiarato volatile viene trattato come due variabili a 32 bit per operazioni di caricamento, memorizzazione, lettura e scrittura.

Inoltre, la modalità di codifica e l’ordine delle due operazioni a 32 bit non sono definite.

Le specifiche incoraggiano le implementazioni a rendere l’operazione atomica ma non la richiedono.

Se la variabile è volatile , la lettura / scrittura è garantita atomica, ma non se la variabile è non volatile.

Alcune implementazioni potrebbero trovare conveniente dividere una singola azione di scrittura su un valore a 64 bit lungo o doppio in due azioni di scrittura su valori adiacenti a 32 bit. Per motivi di efficienza, questo comportamento è specifico per l’implementazione; Le macchine virtuali Java sono libere di eseguire scritture su valori lunghi e doppi atomicamente o in due parti.

Ai fini del modello di memoria del linguaggio di programmazione Java, una singola scrittura su un valore lungo o doppio non volatile viene trattata come due scritture separate: una per ciascuna metà a 32 bit. Ciò può comportare una situazione in cui un thread vede i primi 32 bit di un valore a 64 bit da una scrittura e i secondi 32 bit da un’altra scrittura. Le scritture e le letture di valori volatili lunghi e doppi sono sempre atomici.

JLS 17.7 – Trattamento non atomico di doppio e lungo

Quando più thread accedono a un valore lungo senza sincronizzazione, è necessario utilizzare volatile per garantire che le modifiche apportate da un thread siano visibili ad altri thread e garantire che la lettura / scrittura sia atomica.