Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to create AtomicReference that can be swapped atomically?

Is there any way to implement a type of reference whose value can be exchanged with another atomically?


In Java we have AtomicReference which can be swapped with a local variable but not with another AtomicReference.

You can do:

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

and swap them with a combination of two operations:

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

But this leaves them in an inconsistent state in between, where both contain "hello". Also even if you could swap them atomically, you still could not read them (as a pair) atomically.


What I would like to be able to do is:

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

then

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

to swap the values, and in another thread:

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

and be certain that the output will be either [hello, world] or [world, hello].

Notes:

  • r1 and r2 are paired for this operation, but it's possible that another thread will independently pair, say r1 and another r3 (unfortunately that means I cannot use this solution.)
  • There will be hundreds of thousands of these references, so a global ReentrantLock would be a major bottleneck.
  • rp and otherRP are not necessarily shared between threads, so simply locking them will not work. They could be interned, but the intern pool would need its own synchronization which would be another bottleneck.
  • I have only made groups of 2 references here, but the ability to group 3 or more would be a bonus.

Is it possible to implement a lock-free version of AtomicRefPair? I have a hunch that it isn't, but if not then maybe there is an article somewhere that explains why?


Related: How do I atomically swap 2 ints in C#?

like image 873
finnw Avatar asked Jan 25 '11 21:01

finnw


1 Answers

Have an immutable class holding the pair. That is your atom. Swapping the pair means replacing the atom.

update: your question isn't very clear. but in general, for a concurrent system consisting of multiple variables, one might want

  1. take a snapshot of system state. the snapshot doesn't change once taken.
  2. atomically update system state by changing multiple variables at once. it may be required that there is no other update between my update an a previous snapshot (which my calculation was based on)

you can model your system directly in snapshots, if it doesn't consume too much resources.

like image 121
irreputable Avatar answered Sep 25 '22 08:09

irreputable