/ Java  

Java Multithreading 10: AtomicInteger

In the java.util.concurrent.atomic package after JDK1.5, there are more atomic processing classes.

  1. Primitive types: AtomicInteger, AtomicLong, AtomicBoolean;
  2. Array type: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray;
  3. Reference types: AtomicReference, AtomicStampedRerence, AtomicMarkableReference;
  4. Object attribbutes modification types: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater.

They are mainly used for efficient program processing in high concurrent environments to help us simplify synchronization processing.

The three primitive types of atomic classes: AtomicInteger, AtomicLong, and AtomicBoolean, have similar principles and usage. This blog introduces the usage of primitive types of atomic classes with AtomicInteger.

AtomicInteger

AtomicInteger, an Integer class that provides atomic operations. In the Java language, ++i and i++ are not thread-safe, and when used, it is inevitable to use the synchronized keyword. AtomicInteger uses a thread-safe addition and subtraction operation interface.

Let’s take a look at what AtomicInteger provides us:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// get value
public final int get()

// get value and set a new value
public final int getAndSet(int newValue)

// get value and increment by 1
public final int getAndIncrement()

// get value and decrement by 1
public final int getAndDecrement()

// get value and add delta
public final int getAndAdd(int delta)

Let’s look at the advantages of AtomicInteger through simple examples:

Normal thread synchronization

1
2
3
4
5
6
7
8
9
10
11
class Test {
private volatile int count = 0;

public synchronized void increment() {
count++;
}

public int getCount() {
return count;
}
}

Use AtomicInteger

1
2
3
4
5
6
7
8
9
10
11
class Test {
private AtomicInteger count = new AtomicInteger();

public void increment() {
count.incrementAndGet();
}

public int getCount() {
return count.get();
}
}

From the above example, we can see that using AtomicInteger is thread safe. And because AtomicInteger is implemented by hardware providing atomic operation instructions. In the absence of intense competition, the overhead is smaller and the speed is faster.

Let’s take incrementAndGet() as an example to see how AtomicInteger works.

1
2
3
4
5
6
7
8
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");

private volatile int value;

public final int incrementAndGet() {
return U.getAndAddInt(this, VALUE, 1) + 1;
}

Unsafe is a class provided by java to gain access to the memory address of an object. It is actually an util in AtomicInteger.

Value is a variable used to store integers. It is declared as volatile here to ensure that the current thread can get the latest value of the value during the update operation (in a concurrent environment, the value may have been updated by other threads).

The getAndAddInt() method in Unsafe class:

1
2
3
4
5
6
7
8
9
10
11
public final int getAndAddInt(Object o, long offset, int delta) {
int v;

do {
// obbtain the latest value
v = getIntVolatile(o, offset);
// Use the unsafe native method to achieve efficient hardware-level CAS
} while (!weakCompareAndSetInt(o, offset, v, v + delta));

return v;
}

It uses optimistic lock implementation: volatile + CAS. If unsuccessful update, just continue the loop until success. The efficiency is much higher than lock(pessimistic lock) every time