Есть ли способ реализовать тип ссылки, значение которой можно атомарно обменивать на другую?
В 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
не обязательно являются общими для потоков, поэтому простое их блокирование не будет работать.Они могут быть interned , но для внутреннего пула потребуется собственная синхронизация, что станет еще одним узким местом. - Я сделал только группы из 2 ссылок, но возможность группировать 3 или болеебудет бонусом.
Можно ли реализовать версию без блокировки AtomicRefPair
?У меня есть догадка, что это не так, но если нет, то, может быть, где-то есть статья, которая объясняет, почему?
Related : Как атомарно поменять 2целые числа в C #?