在2个不同的AtomicReferences中交换2个值

时间:2015-02-01 11:38:14

标签: java concurrency

我尝试为2个AtomicReferences实现交换方法。

public void swap(AtomicReference<Object> a, AtomicReference<Object> b) {
    while (true) {
        Object value1 = a.get();
        Object value2 = b.get();

        if (a.compareAndSet(value1, value2) && b.compareAndSet(value2, value1)) return;
    }
}

在我看来,这个解决方案不正确。如果多个线程同时使用此方法,则可能导致以下情形:

T1: ...get(); get(); compareAndSet() == true //-> BREAK (scheduler)
T2: ...get(); get(); compareAndSet() == true; compareAndSet() == true; return;

这意味着,T1设置了a的值,但是通过设置b的值会失败。如果已设置AtomicReference a,T1将重复该过程。

你们中有人有更好的想法,如何实现这样的事情?如果您只有一个AtomicReference,那将很容易。也许使用2个AtomicReference是不可能的,我应该考虑使用一个指向Object []的AtomicReference。

在Scala中,这种方法非常容易实现,因为你有原子块。

class Swappy[A](_a: A, _b: A) {

  @volatile
  var a = Ref(_a)
  @volatile
  var b = Ref(_b)

  def swap(): Unit = {
    atomic {
      implicit tx =>
            val tmp = a
            a = b
            b = tmp
    }
  }

  def elems: (A, A) = (a.single(), b.single())
}

2 个答案:

答案 0 :(得分:1)

我用不同的方法创建了一个解决方案。这应该是100%线程安全的。我转而只使用一个AtomicReference。如果有人能找到更好的方法,请随时写一个答案。 :)

package test;

import java.util.concurrent.atomic.*;

public class ScalaSTMPendant {

    AtomicReference<Object[]> a;

    public ScalaSTMPendant(Object a, Object b) {
        this.a = new AtomicReference<>(new Object[] {a,b});
    }

    public void swap() {
        while (true) {
            Object[] origin = a.get();

            Object[] swapped = new Object[] {origin[1], origin[0]};

            if (a.compareAndSet(origin, swapped)) return;
        }
    }

    public Object[] elems() {
        Object[] temp = a.get();
        return new Object[] {temp[0], temp[1]};
    }
}

答案 1 :(得分:0)

Exchanger会有帮助吗?我不知道是谁交换了什么,但是一个交换器可以帮助你以原子方式进行交换。

此外,上面的scala示例使用ScalaSTM。您可以使用另一个STM实现(甚至ScalaSTM)在Java中执行相同的操作。例如:Multiverse