fin*_*nnw 6 java interlocked atomicreference atomic-swap
有没有办法实现一种类型的引用,其值可以与另一个原子交换?
在Java中,我们AtomicReference可以使用本地变量而不是其他变量进行交换AtomicReference.
你可以做:
AtomicReference r1 = new AtomicReference("hello");
AtomicReference r2 = new AtomicReference("world");
Run Code Online (Sandbox Code Playgroud)
并将它们与两个操作组合交换:
r1.set(r2.getAndSet(r1.get()));
Run Code Online (Sandbox Code Playgroud)
但是这使得它们之间处于不一致状态,两者都包含在内"hello".即使你可以原子地交换它们,你仍然无法原子地读取它们(作为一对).
我希望能做的是:
PairableAtomicReference r1 = new PairableAtomicReference("hello");
PairableAtomicReference r2 = new PairableAtomicReference("world");
AtomicRefPair rp = new AtomicRefPair(r1, r2);
Run Code Online (Sandbox Code Playgroud)
然后
Object[] oldVal, newVal;
do {
oldVal = rp.get();
newVal = new Object[] {oldVal[1], oldVal[0]};
} while (! rp.compareAndSet(oldVal, newVal));
Run Code Online (Sandbox Code Playgroud)
交换值,并在另一个线程中:
AtomicRefPair otherRP = new AtomicRefPair(r1, r2);
System.out.println(Arrays.toString(otherRP.get()));
Run Code Online (Sandbox Code Playgroud)
并确保输出将是[hello, world]或[world, hello].
笔记:
r1并且r2为此操作配对,但是另一个线程可能会独立配对,说r1和另一个r3(不幸的是,这意味着我无法使用此解决方案.)ReentrantLock将是一个主要的瓶颈.rp并且otherRP不一定在线程之间共享,因此简单地锁定它们将不起作用.他们可以被实习,但实习池需要自己的同步,这将是另一个瓶颈.是否可以实现无锁版本AtomicRefPair?我有预感它不是,但如果不是那么也许有一篇文章可以解释为什么?
我不知道是否有一个好的解决方案,但以下丑陋的解决方案可以工作:
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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1640 次 |
| 最近记录: |