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 und r2 werden für diese Operation gepaart, aber es ist möglich, dass ein anderer Thread unabhängig voneinander kombiniert wird, sagen wir r1 und ein anderer r3 (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 und otherRP 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?

War es hilfreich?

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

  1. Machen Sie eine Momentaufnahme des Systemzustands. Der Schnappschuss ändert sich nicht einmal genommen.
  2. 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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top