Java: is there no AtomicFloat or AtomicDouble?

The API docs for the java.util.concurrent package states the following:

[...] Additionally, classes are provided only for those types that are commonly useful in intended applications. For example, there is no atomic class for representing byte. In those infrequent cases where you would like to do so, you can use an AtomicInteger to hold byte values, and cast appropriately. You can also hold floats using Float.floatToIntBits and Float.intBitstoFloat conversions, and doubles using Double.doubleToLongBits and Double.longBitsToDouble conversions.

I'm not claiming it's a convenient solution, but that seems to be the explanation. I suppose you would probably want to wrap an AtomicInteger and provide access methods for getFloat / setFloat etc.


I actually got around writing one. Here you go:

import java.util.concurrent.atomic.AtomicInteger;
import static java.lang.Float.*;

class AtomicFloat extends Number {

    private AtomicInteger bits;

    public AtomicFloat() {
        this(0f);
    }

    public AtomicFloat(float initialValue) {
        bits = new AtomicInteger(floatToIntBits(initialValue));
    }

    public final boolean compareAndSet(float expect, float update) {
        return bits.compareAndSet(floatToIntBits(expect),
                                  floatToIntBits(update));
    }

    public final void set(float newValue) {
        bits.set(floatToIntBits(newValue));
    }

    public final float get() {
        return intBitsToFloat(bits.get());
    }

    public float floatValue() {
        return get();
    }

    public final float getAndSet(float newValue) {
        return intBitsToFloat(bits.getAndSet(floatToIntBits(newValue)));
    }

    public final boolean weakCompareAndSet(float expect, float update) {
        return bits.weakCompareAndSet(floatToIntBits(expect),
                                      floatToIntBits(update));
    }

    public double doubleValue() { return (double) floatValue(); }
    public int intValue()       { return (int) get();           }
    public long longValue()     { return (long) get();          }

}

You could perhaps use an AtomicReference<Float> instead. I think AtomicInteger and AtomicLong get special classes because they're useful for counting.


I'm also surprised there wasn't a built-in solution. The use-case is to get the floating-point sum of values emitted by a collection of concurrent threads without memory use scaling with the number of values. For instance, the concurrent threads are prediction engines and you want to monitor the sum of predicted-minus-truth residuals from all prediction engines in one place. Simultaneous attempts to add to a naive counter would result in lost counts (in exactly the same way as integer counters).

A ConcurrentLinkedQueue can collect the values to sum, but unless there's a thread dedicated to reducing that queue (constantly running result += q.poll() until poll returns null, then q.add(result) and wait a moment for it to fill up again), the size of the queue would grow to the number of values to sum.

Java 8 has DoubleAdder and Guava has AtomicDouble (see comments on other questions), but that doesn't help library developers targeting old Java with minimal dependencies. I looked at a sample of DoubleAdder code and AtomicDouble code, and what I found surprised me: they just retry addition followed by compareAndSet until doing so is not erroneous. The number of threads attempting to write can increase while there's contention, but unless they're in perfect lock-step, some will win the race and get out of the way while others keep retrying.

Here's a Scala implementation of what they do:

class AtomicDouble {
    private val value = new AtomicReference(java.lang.Double.valueOf(0.0))
    @tailrec
    final def getAndAdd(delta: Double): Double = {
        val currentValue = value.get
        val newValue = java.lang.Double.valueOf(currentValue.doubleValue + delta)
        if (value.compareAndSet(currentValue, newValue))
            currentValue.doubleValue
        else
            getAndAdd(delta)   // try, try again
    }
}

and an attempted Java translation:

class AtomicDouble {
    private AtomicReference<Double> value = new AtomicReference(Double.valueOf(0.0));
    double getAndAdd(double delta) {
        while (true) {
            Double currentValue = value.get();
            Double newValue = Double.valueOf(currentValue.doubleValue() + delta);
            if (value.compareAndSet(currentValue, newValue))
                return currentValue.doubleValue();
        }
    }
}

It works (Scala version tested with hundreds of threads), and provides a way to generalize from Double.

However, I don't see any reason why this would be faster or preferred over synchronizing on write only. A blocking solution would also make some threads wait while others increment the counter, but with a guarantee that all will eventually finish (no reliance on imperfect timing) and no wasted CPU (don't compute the sum until you know you're allowed to update it). So why do this?