Subclass of AtomicReference with atomic function application

Update: Now that https://github.com/bionicspirit/scala-atomic is available, I have less of a need for this.

Am I doing anything bad? I wrote this class to allow modifying an atomic reference with the assurance that two threads modifying it will not step on each other's toes. To illustrate:

val x = new AtomicRef(List.empty[String])
def compute(s: String) = { Thread.sleep(1000); s }
def updateX(s: String) = x.transform(strings => compute(s) :: strings)


The idea is to guarantee that if two threads call updateX many times, all the strings passed to updateX will wind up in x.

run is like transform but it lets you return a value to the caller other than the value you're setting into the reference.

Here is the class:

/**
* A subclass of java.util.concurrent.atomic.AtomicReference[A]
* that adds the ability to atomically modify its value relative to itself.
*/
class AtomicRef[A](init: A) extends java.util.concurrent.atomic.AtomicReference[A](init) {
/**
* Update the value atomically by applying a function to it.
* Uses compareAndSet and will keep trying until it succeeds.
*/
final def transform(f: A => A): A = run { a =>
val ret = f(a)
(ret, ret)
}
/**
* Update the value atomically by applying a computation to it.
* The computation returns a pair of values, of which the
* AtomicRef is updated to the first.
* Uses compareAndSet and will keep trying until it succeeds.
* @return the second value of the computation
*/
@annotation.tailrec final def run[B](f: A => (A, B)): B = {
val a = get
val (a2, b) = f(a)
if(compareAndSet(a, a2)) b
else {
run(f)
}
}
}


To put it in different terms, this sort of abstracts over doing something like this (in Java; List here is a fictional immutable list):

AtomicReference<List<String>> ref = new AtomicReference<List<String>>(new List());
void update(String s) {
while(true) {
List<String> a = ref.get;
// now do "f(a)"
Thread.sleep(1000); // pretend it takes a long time to run the computation
List<String> b = a.prepend(s);
if(compareAndSet(a, b)) return b;
else {
// loop the while instead of tail recursion
}
}
}

• This cannot be really called atomic, especially the run function; if another thread has a reference to this AtomicReference it can modify the value from under your nose. What is the intent of this class exactly? – fge Jun 17 '13 at 7:55
• Hi @fge, apologies for not describing the intent before. I added it to the question text. Is it clear? – nafg Jun 18 '13 at 8:59
• @fge It's true another thread can modify the value while the computation is running. But then compareAndSet will fail (return false) and we will try again! compareAndSet means don't store the result of the computation unless the value still is what the computation thought it was! – nafg Jun 18 '13 at 9:01
• Uh, OK, I don't understand scala well enough to really comment :/ – fge Jun 18 '13 at 9:02
• @fge thanks anyway, I added a Java snippet that illustrates the pattern, except now having functions it doesn't abstract over the operation. – nafg Jun 19 '13 at 17:08

However I have some doubts if such a class is really useful. If the computations are potentially long running, the performance advantage of using AtomicReference instead of some standard synchronization primitive is negligible. Moreover, if there are several updating threads, it will result in repeated recomputation, wasting CPU power on it. So using plain synchronized on some private lock object (so that no other part of code can lock on it) seems simpler, safer and with better performance.