Возможно создать атомареференцию, которая может быть атомно обременена?

StackOverflow https://stackoverflow.com/questions/4799086

Вопрос

Есть ли способ реализовать тип ссылки, значение которого можно обменять с другой атомной?


На Java у нас есть AtomicReference которая может быть поменена на локальную переменную, но не на другой AtomicReference.

Ты можешь сделать:

AtomicReference r1 = new AtomicReference("hello");
AtomicReference r2 = new AtomicReference("world");

и обменивать их комбинацией двух операций:

r1.set(r2.getAndSet(r1.get()));

Но это оставляет их в непоследовательном состоянии между ними, где оба содержат "hello". Анкет Кроме того, даже если бы вы могли поменять их атомно, вы все равно не могли бы прочитать их (как пара) атомно.


Я хотел бы иметь возможность:

PairableAtomicReference r1 = new PairableAtomicReference("hello");
PairableAtomicReference r2 = new PairableAtomicReference("world");
AtomicRefPair rp = new AtomicRefPair(r1, r2);

тогда

Object[] oldVal, newVal;
do {
    oldVal = rp.get();
    newVal = new Object[] {oldVal[1], oldVal[0]};
} while (! rp.compareAndSet(oldVal, newVal));

обмениваться значениями и в другой ветке:

AtomicRefPair otherRP = new AtomicRefPair(r1, r2);
System.out.println(Arrays.toString(otherRP.get()));

и будьте уверены, что вывод будет либо [hello, world] или же [world, hello].

Заметки:

  • r1 а также r2 в паре для этой операции, но вполне возможно, что другая поток будет независимо, скажем, скажем, r1 и другой r3 (К сожалению, это означает, что я не могу использовать это решение.)
  • Будут сотни тысяч этих ссылок, поэтому глобальный ReentrantLock было бы главным узким местом.
  • rp а также otherRP не обязательно разделяются между потоками, поэтому простой блокировка их не будет работать. Они могут быть Интернизован, но бассейн стажеров понадобится собственная синхронизация, которая будет еще одним узким местом.
  • Я сделал здесь только группы из 2 ссылок, но способность к группе 3 или более была бы бонусом.

Возможно ли реализовать версию без блокировки AtomicRefPair? У меня есть догадка, что это не так, но если нет, то, может быть, где -то есть статья, которая объясняет, почему?


Связанный: Как я могу атомно обмениваться 2 INT в C#?

Это было полезно?

Решение

Я не знаю, есть ли хорошее решение, но следующее уродливое можно сработать:

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;
}
  • Используйте MyReference вместо AtomicReference.
  • Он использует много замков, но ни один из них не является глобальным.
  • Он приобретает замки в фиксированном порядке, так что он не имеет тупика.
  • Он компилирует с использованием Ломбока и гуавы (воспринимайте его как псевдокод без них).

Другие советы

Иметь неизменную класс, держащую пару. Это ваш атом. Обмен парой означает замену атома.

Обновление: ваш вопрос не очень ясен. Но в целом для одновременной системы, состоящей из нескольких переменных, можно хотелось бы хотеть

  1. Сделайте снимок состояния системы. Снимок не меняется однажды.
  2. Атомальное обновление системы системы путем изменения нескольких переменных одновременно. Возможно, потребуется, чтобы между моим обновлением не было другого обновления A предыдущего снижения (который был основан на моем расчете)

Вы можете смоделировать свою систему непосредственно в снимках, если она не потребляет слишком много ресурсов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top