Lei non è stato inizializzato il riferimento nel primo esempio, probabilmente dovrebbe essere:
public class Internet {
AtomicReference<String> address = new AtomicReference<String>();
public String getAddress(){
String s = address.get();
return s == null ? null : s.toString();
}
public void setAddress(String address) {
this.address.set(address);
}
}
Dove si trova l'restrizione di accesso è importante. Se metti il controllo all'interno dell'oggetto a cui si accede, allora può avere il controllo esclusivo dei suoi invarianti, che è molto meno fragile che fare affidamento sui thread per sincronizzarli tutti correttamente, dove un thread di accesso mal funzionante può corrompere la cosa a cui si accede. Quindi il primo esempio è molto meglio su quell'account.
Se si modifica il secondo esempio in modo che l'oggetto ha il controllo su un proprio blocco (in modo che non si basa su discussioni accedervi a farlo in modo sicuro), in questo modo:
public class Internet {
private final Object lock = new Object();
private String s;
public String getAddress() {
synchronized(lock) {
return s;
}
}
public void setAddress(String s) {
synchronized(lock) {
this.s = s;
}
}
}
allora è una più stretta confronto, uno si basa sul blocco e l'altro sui riferimenti atomici. Quello che usa AtomicReference cerca di evitare il blocco usando istruzioni di elaborazione atomica a livello di macchina. Quale è più veloce può dipendere dal tuo hardware e jvm e il carico di elaborazione, in genere l'approccio atomico dovrebbe essere più veloce. L'approccio sincronizzato è un meccanismo più generale; con il blocco sincronizzato è possibile raggruppare più assegnazioni molto più facilmente, dove con riferimenti atomici è molto più coinvolto.
As James says in his answer, con la sincronizzazione i thread sono in attesa di un blocco; non c'è il timeout e il deadlock è possibile. Con il riferimento atomico, il thread esegue la modifica senza attendere un blocco condiviso.
Il modo più semplice e migliore performance per implementare questo potrebbe essere quella di organizzare il codice in modo da poter rendere l'oggetto immutabile, quindi si dovrebbe evitare ogni blocco, occupato-attesa, e l'aggiornamento della cache:
public final class Internet {
private final String s;
public Internet(String s) {
this.s = s;
}
public String getAddress() {return s;}
}
In ordine decrescente di preferenza:
- Preferire l'immutabilità quando possibile.
- Per il codice che non può essere immutabile, provare a limitare la mutazione a un thread.
- Se solo una cosa deve passare attraverso i thread, utilizzare l'approccio atomico.
- Se più modifiche ai thread devono verificarsi insieme indisturbate da altri thread, utilizzare il blocco.
È funzionalmente lo stesso, se è quello che stai chiedendo. Il modello di concorrenza è diverso. –
Vedere http://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html "Per questa classe semplice, la sincronizzazione è una soluzione accettabile, ma per una classe più complicata, potremmo voler evitare l'impatto sulla durata di sincronizzazione non necessaria. " Come sopra, funzionalmente sono uguali. – jdv