Java Atomic

In Java, atomic variables and operations used in concurrency. The multi-threading environment leads to a problem when concurrency is unified. The shared entity such as objects and variables may be changed during the execution of the program. Hence, they may lead to inconsistency of the program. So, it is important to take care of the shared entity while accessing concurrently. In such cases, the atomic variable can be a solution to it. In this section, we will discuss atomic classes, atomic variables, atomic operations, along with examples.

Before moving ahead in this section, ensure that you are aware of thread, synchronization, and lock in Java.

Java Atomic Classes

Java provides a java.util.concurrent.atomic package in which atomic classes are defined. The atomic classes provide a lock-free and thread-safe environment or programming on a single variable. It also supports atomic operations. All the atomic classes have the get() and set() methods that work on the volatile variable. The method works the same as read and writes on volatile variables.

The package provides the following atomic classes:

ClassDescription
AtomicBooleanIt is used to update boolean value atomically.
AtomicIntegerIt is used to update integer value atomically.
AtomicIntegerArrayAn int array in which elements may be updated atomically.
AtomicIntegerFieldUpdaterA reflection-based utility that enables atomic updates to designated volatile int fields of designated classes.
AtomicLongIt is used to update long value atomically.
AtomicLongArrayA long array in which elements may be updated atomically.
AtomicLongFieldUpdaterA reflection-based utility that enables atomic updates to designated volatile long fields of designated classes.
AtomicMarkableReferenceAn AtomicMarkableReference maintains an object reference along with a mark bit, that can be updated atomically.
AtomicReferenceAn object reference that may be updated atomically.
AtomicReferenceArrayAn array of object references in which elements may be updated atomically.
AtomicReferenceFieldUpdaterA reflection-based utility that enables atomic updates to designated volatile reference fields of designated classes.
AtomicStampedReferenceAn AtomicStampedReference maintains an object reference along with an integer "stamp", that can be updated atomically.
DoubleAccumulatorOne or more variables that together maintain a running double value updated using a supplied function.
DoubleAdderOne or more variables that together maintain an initially zero double sum.
LongAccumulatorOne or more variables that together maintain a running long value updated using a supplied function.
LongAdderOne or more variables that together maintain an initially zero long sum.

Objects of these classes represent the atomic variable of int, long, boolean, and object reference respectively. The atomic classes have some common methods are as follows:

MethodsDescription
set()It is used to set the value.
get()It is used to get the current value.
lazySet()Eventually sets to the given value.
compareAndSetAtomically sets the value to the given updated value if the current value == the expected value.

Atomic Operations

Those operations that always execute together is known as the atomic operations or atomic action. All the atomic operations either execute effectively happens all at once or it does not happen at all. Three key concepts are associated with atomic actions in Java are as follows:

1. Atomicity deals with which actions and sets o actions have invisible For example, consider the following code snippet:

In the above code, the behavior of running increment() and decrement() concurrently is undefined and not predictable.

2. Visibility determines when the effect of one thread can be seen by another. For example, consider the following code snippet:

In the above code, it is possible that thread T2 will never stop even after thread T1 sets done to true. Also, not that there is no synchronization between threads.

3. Ordering determines when actions in one thread occur out of order with respect to another thread.

The order that fields a and b appear in thread T2 may differ from the order they were set in Thread T1.

Let's understand it through an example.

In the above code snippet, we have declared an int type variable count and inside the method incrementCount() assigned it to 1. In such a case, either all happen together or would not happen at all. Hence, it represents an atomic operation and the operation is known as atomicity.

Let's consider another code snippet.

It seems that it is also an atomic operation but not so. It is a linear-operation that consists of three operations i.e. read, modify, and write. Therefore, it can execute partially. But if we are using the above code in a multi-threaded environment, it creates a problem.

Suppose, we have called the above code in a single-threaded environment, the updated value of count will be 2. If we call the above method by two separate threads, they both access the variable at the same time and also update the value of count simultaneously. To avoid this situation, we use atomic operation.

Java supports several types of atomic actions, are as follows:

  • Volatile variables
  • Low-level atomic operations (unsafe)
  • Atomic classes

Let's see how can we create an atomic operation.

Atomic Variable

The atomic variable allows us to perform an atomic operation on a variable. Atomic variables minimize synchronization and help avoid memory consistency errors. Hence, it ensures synchronization.

The atomic package provides the following five atomic variables:

  • AtomicInteger
  • AtomicLong
  • AtomicBoolean
  • AtomicIntegerArray
  • AtomicLongArray

The Need of Atomic Variable

Let's consider the following code.

Counter.java

Output:

4

The above program gives the expected output if it is executed in a single-threaded environment. A multi-threaded environment may lead to unexpected output. The reason behind it that when two or more threads try to update the value at the same time then it may not update properly.

Java offers two solutions to overcome this problem:

  • By using lock and synchronization
  • By using atomic variable

Let's create a Java program and use an atomic variable to overcome the problem.

By using Atomic Variable

AtomicExample.java

Output:

4

Synchronized Vs. Atomic Vs. Volatile

SynchronizedAtomicVolatile
It applies to methods only.It applies to variables only.It also applies to variables only.
It ensures visibility along with atomicity.It also ensures visibility along with atomicity.It ensures visibility, not atomicity.
We can't achieve the same.We can't achieve the same.It stores in RAM, so accessing volatile variables is fast. But it does not provide thread-safety and synchronization.
It can be implemented as a synchronized block or a synchronized method.We can't achieve the same.We can't achieve the same.
It can lock the same class object or a different class object.We can't achieve the same.We can't achieve the same.





Latest Courses