Why are two AtomicIntegers never equal?

This is partly because an AtomicInteger is not a general purpose replacement for an Integer.

The java.util.concurrent.atomic package summary states:

Atomic classes are not general purpose replacements for java.lang.Integer and related classes. They do not define methods such as hashCode and compareTo. (Because atomic variables are expected to be mutated, they are poor choices for hash table keys.)

hashCode is not implemented, and so is the case with equals. This is in part due to a far larger rationale that is discussed in the mailing list archives, on whether AtomicInteger should extend Number or not.

One of the reasons why an AtomicXXX class is not a drop-in replacement for a primitive, and that it does not implement the Comparable interface, is because it is pointless to compare two instances of an AtomicXXX class in most scenarios. If two threads could access and mutate the value of an AtomicInteger, then the comparison result is invalid before you use the result, if a thread mutates the value of an AtomicInteger. The same rationale holds good for the equals method - the result for an equality test (that depends on the value of the AtomicInteger) is only valid before a thread mutates one of the AtomicIntegers in question.


I suspect that comparing the values is a no-go since there's no way to do it atomically in a portable fashion (without locks, that is).

And if there's no atomicity then the variables could compare equal even they never contained the same value at the same time (e.g. if a changed from 0 to 1 at exactly the same time as b changed from 1 to 0).


I would argue that because the point of an AtomicInteger is that operations can be done atomically, it would be be hard to ensure that the two values are compared atomically, and because AtomicIntegers are generally counters, you'd get some odd behaviour.

So without ensuring that the equals method is synchronised you wouldn't be sure that the value of the atomic integer hasn't changed by the time equals returns. However, as the whole point of an atomic integer is not to use synchronisation, you'd end up with little benefit.


On the face of it, it seems like a simple omission but it maybe it does make some sense to actually just use the idenity equals provided by Object.equals

For instance:

AtomicInteger a = new AtomicInteger(0)
AtomicInteger b = new AtomicInteger(0)

assert a.equals(b)

seems reasonable, but b isn't really a, it is designed to be a mutable holder for a value and therefore can't really replace a in a program.

also:

assert a.equals(b)
assert a.hashCode() == b.hashCode()

should work but what if b's value changes in between.

If this is the reason it's a shame it wasn't documented in the source for AtomicInteger.

As an aside: A nice feature might also have been to allow AtomicInteger to be equal to an Integer.

AtomicInteger a = new AtomicInteger(25);

if( a.equals(25) ){
    // woot
}

trouble it would mean that in order to be reflexive in this case Integer would have to accept AtomicInteger in it's equals too.