[concurrency-interest] Re: AtomicInteger and AtomicLong should implement Number

Doug Lea dl@cs.oswego.edu
Mon, 12 Jan 2004 08:12:23 -0500

> A tangential comment on this : Would it make sense to have XYZ.atomicX 
> that would return a atomic version of X akin to 
> Collections.synchronizedMap?

We actually do something like this, although not so conveniently, for
more varieties of "X" than you probably had in mind.  Explaining this
requires some backing up...

As it says in the atomics package docs, an atomic is basically just a
volatile variable supporting an extra operation, CAS (compareAndSet),
with two variants plus some derived forms. Further, only variables of
some volatile types and be atomic. You can't CAS a byte, char or short
variable because of type-width issues, and can't reliably CAS a float
or double because of floating point equality issues (e.g.,
NaNs). These restrictions are merely hardware artifacts on modern
processors, but don't have decent workarounds, so we don't try to
cover them up.

In a language that was designed from the ground up to support this,
CAS might be a syntactic form.  Although coming up with good syntax is
itself challenging. The best I recall anyone being able to come up
with is "var ?= expected? newValue", which is not only strange
looking, but doesn't supply the boolean success/failure flag that you
usually need.

Because we couldn't do this syntactically, and because CAS is an
"lvalue" operation, not a function, we instead have to supply a range
of forms that cover all the cases that can arise: The most commonly
used are the stand-alone single-variable classes like AtomicInteger.
Similarly for array elements, with AtomicIntegerArray etc.  But you
can also "latch on" CAS capabilities to any existing volatile field of
any class using the reflection-based AtomicIntegerFieldUpdater etc. It
would have in principle minimally sufficed to support only the updater
versions, but not only are they very awkward to use, they can in some
contexts encounter noticeable reflection-based overhead. 

So, depending on the "X" you have in mind, one of these versions will
apply to give you an atomic form of that X. I don't see a way to make
a uniform API that figures out which of these versions to create though.

As irregular extensions to the otherwise regular structure of single
variables, arrays, and fields of int, long, and reference, we provide
AtomicBoolean, AtomicMarkedReference, and AtomicStampedReference that
deal only with single variables, but cannot be made to apply to arrays
or fields. These are special-cased because on some platforms, some
JVMs may be able to deal with them more efficiently than you could
yourself by building them from the other supplied classes.

Digressing: The implementation side of this is a very similar story.
It might have been nicest to add CAS bytecodes, but instead, in the
reference implmentation (hotspot), we rely on an internal
intrinsics-extension glue API (wrongly/misleadingly called "Unsafe")
that allows trusted code in JDK java.* packages to issue what amounts
to bytecode extensions that understood only by a particular JVM.

Further digressing: The intrinsics API was originally developed mainly
to conjunction with the java.nio package, that presented similar
problems in sometimes needing to deal with direct-mapped IO buffers,
etc in ways that cannot be expressed using bytecodes. Given the
resistance to changing/adding JVM bytecodes, this API probably ought
to be reworked and standardized in some future JCP JSR as an
alternative providing a uniform basis for low-level extensions. But
the cases where this is needed are rare enough that it might not be
worth the effort to standardize.  (Most such cases can be handled
using JNI, which is already standardized, but for atomics, nio
buffers, etc., you need the JVM to "understand" the operation
semantics to implement them efficiently.)