Möglich, um Atomicreference zu schaffen, die atomisch ausgetauscht werden können?
-
24-10-2019 - |
Frage
Gibt es eine Möglichkeit, eine Art von Referenz zu implementieren, deren Wert mit einem anderen atomarer ausgetauscht werden kann?
In Java haben wir AtomicReference
die mit einer lokalen Variablen ausgetauscht werden kann, aber nicht mit einer anderen AtomicReference
.
Du kannst tun:
AtomicReference r1 = new AtomicReference("hello");
AtomicReference r2 = new AtomicReference("world");
und tauschen Sie sie mit einer Kombination von zwei Operationen aus:
r1.set(r2.getAndSet(r1.get()));
Dies lässt sie jedoch in einem inkonsistenten Zustand dazwischen, wo beide enthalten "hello"
. Auch wenn Sie sie atomisch austauschen könnten, konnten Sie sie (als Paar) immer noch nicht atomisch nicht lesen.
Was ich gerne tun möchte, ist:
PairableAtomicReference r1 = new PairableAtomicReference("hello");
PairableAtomicReference r2 = new PairableAtomicReference("world");
AtomicRefPair rp = new AtomicRefPair(r1, r2);
dann
Object[] oldVal, newVal;
do {
oldVal = rp.get();
newVal = new Object[] {oldVal[1], oldVal[0]};
} while (! rp.compareAndSet(oldVal, newVal));
Um die Werte und in einem anderen Thread auszutauschen:
AtomicRefPair otherRP = new AtomicRefPair(r1, r2);
System.out.println(Arrays.toString(otherRP.get()));
und stellen Sie sicher, dass die Ausgabe entweder sein wird [hello, world]
oder [world, hello]
.
Anmerkungen:
r1
undr2
werden für diese Operation gepaart, aber es ist möglich, dass ein anderer Thread unabhängig voneinander kombiniert wird, sagen wirr1
und ein andererr3
(Leider bedeutet das, dass ich nicht verwenden kann diese Lösung.)- Es wird Hunderttausende dieser Referenzen geben, also global
ReentrantLock
wäre ein großer Engpass. rp
undotherRP
werden nicht unbedingt zwischen Threads geteilt, daher funktioniert das Einsperrung einfach nicht. Sie könnten sein interniert, Aber der Praktikantenpool würde eine eigene Synchronisation benötigen, die ein weiterer Engpass wäre.- Ich habe hier nur Gruppen von 2 Referenzen gemacht, aber die Fähigkeit, Gruppe 3 oder mehr zu haben, wäre ein Bonus.
Ist es möglich, eine lock-freie Version von zu implementieren AtomicRefPair
? Ich habe eine Ahnung, die es nicht ist, aber wenn nicht, gibt es vielleicht irgendwo einen Artikel, der erklärt, warum?
Verwandt: Wie tausche ich atomar 2 INTs in C#aus?
Lösung
Ich weiß nicht, ob es eine schöne Lösung gibt, aber der folgende hässliche könnte funktionieren:
public final class MyReference<T> extends ReentrantLock implements Comparable<MyReference<T>> {
public MyReference() {
id = counter.incrementAndGet();
}
public void swap(MyReference<T> other) {
if (id < other.id) {
lock();
other.lock();
} else {
other.lock();
lock();
}
final T tmp = value;
value = other.value;
other.value = tmp;
unlock();
other.unlock();
}
public static <T> List<T> consistentGet(List<MyReference<T>> references) {
final ArrayList<MyReference<T>> sortedReferences = Lists.newArrayList(references);
Collections.sort(sortedReferences);
for (val r : sortedReferences) r.lock();
final List<T> result = Lists.newArrayListWithExpectedSize(sortedReferences.size());
for (val r : references) result.add(r.value);
for (val r : sortedReferences) r.unlock();
return result;
}
@Override
public int compareTo(MyReference<T> o) {
return id < o.id ? -1 : id > o.id ? 1 : 0;
}
private final static AtomicInteger counter = new AtomicInteger();
private T value;
private final int id;
}
- Verwenden Sie MyReference anstelle von Atomicreference.
- Es verwendet viele Schlösser, aber keiner von ihnen ist global.
- Es erwirbt Schlösser in einer festen Reihenfolge, so dass es tadellosfrei ist.
- Es kompiliert mit Lombok und Guava (nimm es als Pseudocode ohne sie).
Andere Tipps
Haben Sie eine unveränderliche Klasse, die das Paar hält. Das ist dein Atom. Das Paar auszutauschen bedeutet, das Atom zu ersetzen.
UPDATE: Ihre Frage ist nicht sehr klar. Im Allgemeinen möchte man für ein gleichzeitiges System, das aus mehreren Variablen besteht
- Machen Sie eine Momentaufnahme des Systemzustands. Der Schnappschuss ändert sich nicht einmal genommen.
- Aktualisieren Sie den Systemstatus atomar, indem Sie mehrere Variablen gleichzeitig ändern. Es kann erforderlich sein, dass es kein anderes Update zwischen meinem Update und einem früheren Snapshot gibt (auf dem meine Berechnung basiert)
Sie können Ihr System direkt in Schnappschüssen modellieren, wenn es nicht zu viele Ressourcen verbraucht.