Race Conditions mit Java-Referenzen
-
04-10-2019 - |
Frage
Die Atom integer, long, boolean usw. werden verwendet, um all Atom-Updates für die jeweiligen Typen zu tun, da es eine Race-Bedingung sein kann, wenn wir ihnen eine Manipulation ausführen, z ++. Aber was die verschiedenen Fälle mit Hinweisen, wo es kann eine solche Rennbedingungen sein?
Die besten Grüße, Keshav
Lösung
AFAIK Referenzen unterliegen nicht die Race-Bedingung, da die JVM gewährleistet, dass die Referenz Update ist eine atomare Operation (im Gegensatz zu beispielsweise einem long
aktualisieren, wo die unteren und oberen 4 Byte in zwei getrennten Schritten aktualisiert werden). Der einzige kritische Fall, wie SLaks erwähnt, ist compareAndSet
, die von Natur aus nicht atomar ist. Dass sehr selten mit einheimischen Referenzen verwendet, aber es ist eine bekannte Redewendung mit AtomicReference
, wenn es eine Notwendigkeit, zwei zu aktualisieren ist (oder mehr) logisch codependent Variablen auf einmal. Java Concurrency in Practice , Abschnitt 15.3.1 veröffentlicht ein Beispiel dafür, eine AtomicReference
mit zwei Variablen zu aktualisieren (in einer einfachen Klasse gespeichert) in einer atomaren Operation.
Der Hauptgrund für die Existenz von AtomicReference
- abgesehen von Konsistenz von Schnittstellen - ist Sichtbarkeit und sichere Veröffentlichung . In diesem Sinne ist eine atomare Variable ist ein „besserer volatile
“.
Andere Tipps
Operationen wie ++
unterliegen Rennbedingungen, weil sie mehr diskreten Operationen (holen, erhöht, zu speichern) einzubeziehen.
Einstellen einer Referenz (a = b
) ist ein Einzelbetrieb und ist somit nicht unter Rennbedingungen.
Operationen auf Referenztypen (a.someMethod()
) können tun, was sie wollen und können oder nicht unter Rennbedingungen sein.
Für Zweck Lernen habe ich ein ConcurrentLinkQueue AtomicReference verwenden.
package concurrent.AtomicE;
import java.util.concurrent.atomic.AtomicReference;
public class ConcurrentLinkQueue<V> {
private final AtomicReference<Node> firstNodePointer = new AtomicReference<Node>();
public void fastOffer(final V data){
final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
System.out.println(newNode);
AtomicReference<Node> pointer = firstNodePointer;
for(;;){
if(pointer.get() == null){
if(pointer.compareAndSet(null,newNode)){
return;
}
}
pointer = pointer.get().getNext();
}
}
private static class Node<V>{
private AtomicReference<Node> next = new AtomicReference<Node>();
private volatile V data = null;
private String threadName = "";
Node(V data1,String threadName){
this.data = data1;
this.threadName = threadName;
}
@Override
public String toString() {
return "threadName=" + threadName +
", data=" + data;
}
private AtomicReference<Node> getNext() {
return next;
}
private void setNext(AtomicReference<Node> next) {
this.next = next;
}
private V getData() {
return data;
}
private void setData(V data) {
this.data = data;
}
}