Home > Articles > Programming > Java

Java Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

Java Atomic Operations

Last updated Mar 14, 2003.

If you’re looking for more up-to-date information on this topic, please visit our Java article, podcast, and store pages.

This week I was working with a consultant that shared with me his experience in proving that the integer increment operation is not an atomic operation. When an integer is incremented, the following logical steps are performed by the JVM:

  1. Retrieve the value of the integer from memory
  2. Increment the value
  3. Assign the newly incremented value back to the appropriate memory location
  4. Return the value to the caller

So while we write the increment operator in a single line of Java code, such as:

int n = i++;

Each one of the aforementioned steps occurs in the JVM. The danger is that if you have multiple threads that all try to increment the same value, there is a chance that two or more of the threads will get the same value (step 1), then increment it (step 2), and then assign the new value to it (step 3). If two threads increment the number 5 then you would expect to see 7 but instead both increment the number 5, yielding a result of 6, and then assign 6 back to the integer's memory location.

With the release of Java SE 5, Sun included a java.util.concurrent.atomic package that addresses this limitation. And specifically they added the following classes:

Table 1. Java Atomic Classes

Class

Description

AtomicBoolean

A Boolean value that may be updated atomically

AtomicInteger

An int value that may be updated atomically

AtomicIntegerArray

An int array in which elements may be updated atomically

AtomicIntegerFieldUpdater<T>

A reflection-based utility that enables atomic updates to designated volatile int fields of designated classes

AtomicLong

A long value that may be updated atomically

AtomicLongArray

A long array in which elements may be updated atomically

AtomicLongFieldUpdater<T>

A reflection-based utility that enables atomic updates to designated volatile long fields of designated classes

AtomicMarkableReference<V>

An AtomicMarkableReference maintains an object reference along with a mark bit, that can be updated atomically

AtomicReference<V>

An object reference that may be updated atomically

AtomicReferenceArray<E>

An array of object references in which elements may be updated atomically

AtomicReferenceFieldUpdater<T,V>

A reflection-based utility that enables atomic updates to designated volatile reference fields of designated classes

AtomicStampedReference<V>

An AtomicStampedReference maintains an object reference along with an integer "stamp", that can be updated atomically

Each of these atomic classes provides methods to perform common operations, but each one is ensured to be performed as a single atomic operation. For example, rather than incrementing an integer using the standard increment operator, like the following:

int n = ++i;

You can ensure that the (1) get value, (2) increment value, (3) update memory, and (4) assign the new value to n is all accomplished without fear of another thread interrupting your operation by writing you code as follows:

AtomicInteger ai = new AtomicInteger( 5 );
int n = ai.incrementAndGet();

In addition, the AtomicInteger class provides the following operations:

Table 2. AtomicInteger Operations

Method

Description

int addAndGet(int delta)

Add delta to the integer and then return the new value

int decrementAndGet()

Decrement the integer and return its value (--i)

int getAndAdd(int delta)

Return the value and then add delta to it (n = i+delta)

int getAndDecrement()

Return the value and then decrement it (n=i--)

int getAndIncrement()

Return the value and then increment it (n=i++)

int getAndSet(int newValue)

Return the value and then set it to the newValue

If you are working in a multithreaded environment, these operations are more effective and the performance impact is almost negligible. For example, to perform 50 million increments, the raw operation (i++) took about 250ms on my notebook and the same atomic operation too about 850ms. So the impact is almost three times the amount of time, but we are still looking at under a second of processing time to perform 50 million operations.

The other primitive type atomic classes work similarly, see the Javadoc for Java SE 5 for more details.

The AtomicReference class is another key class in multithreaded programming as it wraps an object reference accesses into atomic operations. Specifically it provides the following methods:

Table 3. AtomicReference Operations

Method

Description

V get()

Returns the current value of the object

V getAndSet(V newValue)

Return the current value of the object and set it to the newValue

void set(V newValue)

Sets the value of the object to the newValue

Instead of risking multiple threads concurrently updating the same object, these methods protect you. The following code demonstrates how to use the AtomicReference class:

AtomicReference myObjectRef = new AtomicReference( myObject );
MyObject obj = myObjectRef.get();
MyObject otherObject = myObjectRef.getAndSet( myNewObject );
myObjectRef.set( obj );

Summary

Atomic operations are important to ensuring that multiple threads accessing the same objects can be confident in the integrity of these objects. Before the inception of the Java SE 5 atomic classes, programmers were forced to write synchronized code blocks around multithreaded objects. These synchronized blocks are inefficient and an added burden on the developer. The java.util.concurrent.atomic package relieved this burden by providing atomic equivalents to primitive types as well as object references.