Risposte:
La risposta breve è: No.
Dalla java.util.concurrent.atomicdocumentazione del pacchetto. Per citare:
Gli effetti di memoria per gli accessi e gli aggiornamenti di atomica generalmente seguono le regole per i volatili:
getha gli effetti di memoria della lettura di unavolatilevariabile.setha gli effetti di memoria della scrittura (assegnazione) di unavolatilevariabile.
A proposito, quella documentazione è molto buona e tutto è spiegato.
AtomicReference::lazySetè una nuova operazione (Java 6+) introdotta che ha una semantica irraggiungibile attraverso le volatilevariabili. Vedi questo post per maggiori informazioni.
Esistono diverse differenze e compromessi:
L'uso di AtomicReferenceget / set ha la stessa semantica JMM di un campo volatile (come afferma javadoc), ma AtomicReferenceè un wrapper attorno a un riferimento, quindi qualsiasi accesso al campo comporta un ulteriore inseguimento del puntatore .
L' impronta di memoria viene moltiplicata (presupponendo un ambiente OOP compresso, che è vero per la maggior parte delle macchine virtuali):
AtomicReference = 4b + 16b (intestazione oggetto 12b + campo riferimento 4b)AtomicReferenceoffre un'API più ricca di un riferimento volatile. È possibile recuperare l'API per il riferimento volatile utilizzando un AtomicFieldUpdatero con Java 9 a VarHandle. Puoi anche raggiungere dritto sun.misc.Unsafese ti piace correre con le forbici. AtomicReferencestesso viene implementato usando Unsafe.
Quindi, quando è bello scegliere l'uno rispetto all'altro:
AtomicReference/ AtomicFieldUpdater/ Unsafedove tendi a pagare in leggibilità e rischi per il tuo guadagno in termini di prestazioni. Se questa non è un'area sensibile, cerca semplicemente AtomicReference. Gli autori di librerie utilizzano in genere una combinazione di questi metodi in base a JDK mirati, restrizioni API previste, vincoli di memoria e così via.Il codice sorgente JDK è uno dei modi migliori per rispondere a confusioni come questa. Se si osserva il codice in AtomicReference, utilizza una variabile volatie per l'archiviazione degli oggetti.
private volatile V value;
Quindi, ovviamente, se hai intenzione di usare solo get () e set () su AtomicReference è come usare una variabile volatile. Ma come altri lettori hanno commentato, AtomicReference fornisce ulteriore semantica CAS. Quindi, prima decidi se vuoi la semantica CAS o meno, e se lo fai solo allora usa AtomicReference.
AtomicReferencefornisce funzionalità aggiuntive che non fornisce una semplice variabile volatile. Dopo aver letto l'API Javadoc, lo saprai, ma fornisce anche un blocco che può essere utile per alcune operazioni.
Tuttavia, a meno che tu non abbia bisogno di questa funzionalità aggiuntiva, ti suggerisco di utilizzare un volatilecampo semplice .
volatilecampo può essere usato come qualsiasi altro campo mentre l'accesso al valore AtomicReferencerichiede un passaggio gete setmetodi.
A volte anche se usi solo get e set, AtomicReference potrebbe essere una buona scelta:
Esempio con volatile:
private volatile Status status;
...
public setNewStatus(Status newStatus){
status = newStatus;
}
public void doSomethingConditionally() {
if(status.isOk()){
System.out.println("Status is ok: " + status); // here status might not be OK anymore because in the meantime some called setNewStatus(). setNewStatus should be synchronized
}
}
L'implementazione con AtomicReference ti darebbe gratuitamente una sincronizzazione copia su scrittura.
private AtomicReference<Status> statusWrapper;
...
public void doSomethingConditionally() {
Status status = statusWrapper.get();
if(status.isOk()){
System.out.println("Status is ok: " + status); // here even if in the meantime some called setNewStatus() we're still referring to the old one
}
}
Si potrebbe dire che potresti ancora avere una copia corretta se sostituissi:
Status status = statusWrapper.get();
con:
Status statusCopy = status;
Tuttavia è più probabile che il secondo venga rimosso da qualcuno in futuro durante la "pulizia del codice".