Sunday, September 17, 2023

What is Atomic Operation and Variable in Java? AtomicInteger Counter Example

Hello guys, if you're wondering what is atomic operator in Java and how Atomic variable works then you have come to the right place. Earlier, I have shared difference between atomic, volatile and synchronized in Java and in this article, I will explain What is Atomic operator in Java, What are atomic variables and how to use them. In Java, the reading and writing of 32-bit or smaller quantities are guaranteed to be atomic. By atomic we mean each action takes place in one step and cannot be interrupted. Thus, when we have multithreaded applications, the read and write operations are thread-safe and need not be made synchronized.

For example, the following code is thread safe:
public class ThreadSafe
{
    private int x;
    public void setX(int x)
    {
         this.x = x;
    }
}
However, we should be careful to note that the guarantee applies only to reading and writing. For eg. check the following code snippet:
 
public void increment()
{
        ++this.value;
}
Although the above snippet looks to be atomic operation, it is not. The above instruction actually consists of three instructions:

1) Read current setting of 'value'.
2) Increment the setting.
3) Write the new setting back.

Thus, the above code is not thread-safe. To add to the problem, this mistake is not very easily caught during testing due to two reasons:

1) Threading bugs are difficult to detect and are time consuming.
2) This code snippet might translate into a single instruction on some CPUs and thus work correctly. The problem might arise when tested with other JVMs.

The above code can be made thread-safe by simply synchronizing the code as follows: 
public synchronized void increment()
{
        ++this.value;
}


Though, you can also solve this problem and rewrite this code using AtomicVaraible in Java.
In Java, AtomicInteger is part of the java.util.concurrent.atomic package, and it provides a way to perform atomic operations on an integer value. Atomic operations are thread-safe and ensure that the operation is executed without interference from other threads.
Here's how you can rewrite your code using AtomicInteger:
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicCounter {
    private AtomicInteger value = new AtomicInteger(0);

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

    public int getValue() {
        return value.get();
    }
}


In this code:

We import the java.util.concurrent.atomic.AtomicInteger class.

We create a class called AtomicCounter that contains an AtomicInteger named value initialized to 0.

The increment() method uses the incrementAndGet() method of AtomicInteger to atomically increment the value by 1.
The getValue() method allows you to retrieve the current value of the AtomicInteger.


Now, let's understand in detail what atomic variables are in Java and how to use them:


What is Atomic Variables in Java?

Atomic variables in Java are variables that can be modified atomically, meaning that their operations are guaranteed to be thread-safe without the need for explicit synchronization. These variables are part of the java.util.concurrent.atomic package and are typically used to manage shared state in a multi-threaded environment.


There are several types of atomic variables available in Java, including AtomicInteger, AtomicLong, AtomicBoolean, and more. Each of these provides atomic operations for the respective data type and we will see examples of each of them in coming section. 

What is Atomic Variables in Java?




How to Use Atomic Variables in Java?

In order to use any atomic variable in Java, you need to first, import the appropriate atomic class for the data type you want to work with. For example, AtomicInteger for integers. After that just create an instance of the atomic variable and initialize it with an initial value, if needed and use the provided atomic methods to perform operations on the variable. 

These methods ensure that operations are executed atomically and are thread-safe. After that you can use the get() method to retrieve the current value of the atomic variable.

By using atomic variables like AtomicInteger, you can safely manage shared state in multi-threaded applications without the need for explicit synchronization using synchronized blocks or methods. This improves performance and reduces the likelihood of concurrency-related bugs.


Types of Atomic variables in Java

In Java, apart from AtomicInteger, there are several other atomic classes for different data types in the java.util.concurrent.atomic package. These classes provide atomic operations for various data types, ensuring thread safety without the need for explicit synchronization. Here are some of the commonly used atomic classes:


AtomicLong
This class provides atomic operations for long integers. You can use it to perform atomic increments, decrements, additions, and other operations on long values.

AtomicLong atomicLong = new AtomicLong(0);


AtomicBoolean
This class provides atomic operations for boolean values. You can use it to atomically set and get boolean values.

AtomicBoolean atomicBoolean = new AtomicBoolean(false);


AtomicReference
This class allows you to create atomic references to objects. It's useful for managing shared references safely in a multi-threaded environment.

AtomicReference<String> atomicReference = new AtomicReference<>("initial value");


AtomicIntegerArray
If you need an array of atomic integers, you can use this class to perform atomic operations on individual elements of the array.

AtomicIntegerArray atomicIntArray = new AtomicIntegerArray(10);


AtomicLongArray
Similar to AtomicIntegerArray, this class provides atomic operations for long values in an array.

AtomicLongArray atomicLongArray = new AtomicLongArray(10);


AtomicReferenceArray
If you need an array of atomic references, you can use this class to perform atomic operations on the elements of the array.

AtomicReferenceArray<String> atomicRefArray = new AtomicReferenceArray<>(10);


AtomicStampedReference
This class combines an atomic reference with a stamp (an integer) to manage the reference atomically. It's useful for implementing optimistic locking algorithms.

AtomicStampedReference<String> atomicStampedReference = new AtomicStampedReference<>("initial value", 0);




These atomic classes are essential for building concurrent and thread-safe applications without the complexity of using explicit synchronization primitives like synchronized blocks or methods. They help you avoid common threading issues such as race conditions and deadlocks while ensuring high-performance multi-threaded code.


That's all about what is atomic operator in Java and what are Atomic variables in Java. Atomic variables in Java, available in the java.util.concurrent.atomic package, provide a powerful mechanism for safely managing shared state in multi-threaded applications. They offer thread-safe operations on various data types, eliminating the need for explicit synchronization and reducing the risk of common concurrency issues, such as race conditions and deadlocks.

Some of the commonly used atomic classes include AtomicInteger for integers, AtomicLong for long integers, AtomicBoolean for boolean values, AtomicReference for atomic references to objects, and array variants like AtomicIntegerArray, AtomicLongArray, and AtomicReferenceArray. Additionally, AtomicStampedReference combines an atomic reference with a stamp for optimistic locking scenarios.

By using atomic variables, developers can write more efficient and reliable concurrent code, enhancing the performance and scalability of multi-threaded applications while maintaining data integrity and safety. These classes are an integral part of Java's concurrency framework and are essential tools for building robust, multi-threaded Java applications.

1 comment:

  1. What is difference between atomic variable and volatile variable?

    ReplyDelete