AtomicInteger
Explore the AtomicInteger class to learn how it enables atomic read-modify-write operations without locks, improving thread performance. Understand its differences from int and discover how to simulate atomic byte and float types using AtomicInteger, enhancing your Java concurrency skills for interviews.
If you are interviewing, consider buying our number#1 course for Java Multithreading Interviews.
Overview
The AtomicInteger class represents an integer value that can be updated atomically, i.e. the read-modify-write operation can be executed atomically upon an instance of AtomicInteger. The class extends Number.
AtomicInteger makes for great counters as it uses the compare-and-swap (CAS) instruction under the hood which doesn’t penalize threads competing for access to the same data with suspension as locks do In general, suspension and resumption of threads involves significant overhead and under low to moderate contention non-blocking algorithms that use CAS outperform lock-based alternatives.
You can find more details on non-blocking synchronization and atomics here.
Performance
To demonstrate the performance of AtomicInteger we can construct a crude test, where a counter is incremented a million times by ten threads to reach a total of ten million. We’ll time the run for an AtomicInteger counter and an ordinary int counter. The widget below outputs the results:
Difference with int
Remember that AtomicInteger isn’t equivalent to int. Specifically, AtomicInteger class doesn’t override equals() or hashcode() and each instance is distinct. AtomicInteger can’t be used as a drop-in replacement for an int or Integer. This is demonstrated by the widget below:
Using AtomicInteger to simulate atomic byte
Primitive scalars are only available as AtomicInteger or AtomicLong but we can use AtomicInteger to create types that simulate atomic byte. The byte data type is an 8-bit signed two’s complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive).
In the following widget we create a class AtomicByte which internally uses an integer to store a byte representation. The class offers two methods shiftLeft() and shiftRight() that move the bit pattern by one bit left or right respectively in a thread-safe manner and without using locks. The listing appears with comments to explain the working of the class.
The class AtomicByte can be retrofitted with more fancy bit manipulation functionality if desired and without involving any locks.
Using AtomicInteger to simulate atomic float
An equivalent atomic class for float primitive type doesn’t exist, however, we can simulate one using AtomicInteger as we did for the primitive type byte. The float data type is a single-precision 32-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion. Float can be used instead of type double if you need to save memory in large arrays of floating point numbers. This data type should never be used for precise values, such as currency. For that, you will need to use the java.math.BigDecimal class instead.
To create our custom AtomicFloat type, we extend from the class Number and override several of its functions. Under the hood, we save the floating point’s bit representation in an instance of AtomicInteger. The class listing appears below with comments for explanation:
The AtomicByte and AtomicFloat classes in this lesson are shown for instructional purposes only. If you need to use these primitive types atomically, you can find well-written and well-tested libraries on the internet.