Atomic reference in Java
The AtomicReference is a class in Java that offers an object reference that can be read and written atomically. The term atomic means that when multiple thread tries to change the same AtomicReference, only one of the threads would be able to reach it and thus it will not end up in an inconsistent state.
Atomic reference can be utilized when there is a need for an atomic(thread-safe) task on the reference, for which the monitor-based synchronization is unsuitable. For example, the atomic reference can be used if there is a need to set the specific variable only when the object's state changes during processing.
Atomic reference can also be used when updating an immutable object accessed by multiple threads is needed by simply substituting it with a new copy shared among these threads.
Apart from thread safety, the Atomic reference can be utilized when sharing an object between lambda invocations is needed.-
- The object reference presented by the AtomicReference can be updated atomically.
- The AtomicReference class is in the Java.util.concurrent.atomic package.
- The AtomicReference class contains the get() and set() functions that operate similarly to those that read and write on the volatile fields.
- Atomic reference enables lock-free thread-safe programming or environment on a single variable.
Note: It is not necessary to utilize the atomic reference in all the multi-threaded applications. Atomic reference can be used when there is a need to guard a single variable.
Constructors of AtomicReference
Please go through the section below, where we have listed the constructors which can be utilized in the AtomicReference class.
Sr.No. | Constructor | Detail |
- | AtomicReference() | It will create a new Atomic Reference with the initial value as null. |
- | AtomicReference(V initialValue) | It will create a new Atomic Reference with the specified initial value. |
Methods of AtomicReference
Please go through the section below, where we have listed the methods for the AtomicReference class.
Sr.No. | Methods | Detail |
- | accumulateAndGet(V v, BinaryOperator<V> accumulatorFunction) | It will atomically modify or update the current value by employing the given method for the current and given values and return the updated value. |
- | compareAndSet(V expect, V update) | It will atomically set the value to the given updated value when the current value == expected value. |
- | get() | It is used to get the current value. |
- | getAndAccumulate(V v, BinaryOperator<V> accumulatorFunction) | It will atomically modify or update the current value by employing the given method to the current and given values and return the previous value. |
- | getAndSet(V newValue) | It will atomically set the given value and will return the older value. |
- | getAndUpdate(UnaryOperator<V> updateFunction) | It will atomically update or modify the current value with the results of applying the given method and return the previous value. |
- | lazySet(V newValue) | It will eventually be set to the given value. |
- | set(V newValue) | It will be set to the given value. |
- | toString() | It will return the String representation of the specified value. |
- | updateAndGet(UnaryOperator<V> updateFunction) | It will atomically update or modify the current value with the results of applying the given method and return the updated or modified value. |
- | weakCompareAndSet(V expect, V update) | It will atomically set the value to the specified updated value when the current value == expected value. |
How to create an instance of AtomicReference?
Please go through the section below, where we have shown various approaches to create an instance of the Atomic reference in Java.
- Instance of AtomicReference
AtomicReference aReference = new AtomicReference();
- Instance of AtomicReference with an initial Reference
String initialReference = " String of atomic reference with initial reference ";
AtomicReference atomicReference = new AtomicReference(initialReference);
- Instance of Typed AtomicReference
AtomicReference<String> atomicReference =new AtomicReference<>();
- An instance of Typed AtomicReference with an initial Reference
String initialReference = "String of typed atomic reference with initial reference";
AtomicReference<String> atomicStringReference = new AtomicReference<String>(initialReference);
Example1
Please go through a simple example of the Atomic reference given below.
FileName: AtomicReferenceTest.java
//Import the required package
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest {
// main method
public static void main(String[] args) {
// Create an instance of atomic reference
AtomicReference<Integer> atomicReference = new AtomicReference<>();
// set the value
atomicReference.set(1500);
// get and display the value
int val = atomicReference.get();
System.out.println("The value is " +val);
}
}
Output:
The value is 1500
Example 2
Now, go through another example given below in which we have utilized the getAndSet() function, which atomically sets the object to a new value and returns the previous value
FileName: AtomicReferenceTest1.java
//Import the required package
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest1 {
// main method
public static void main(String[] args) {
// Create an instance of atomic reference
AtomicReference<String> atomicReference = new AtomicReference<>();
// set the value
atomicReference.set("Old String of atomic reference");
//gets and sets the atomic reference with a new value
String oldString = atomicReference.getAndSet("New String of atomic reference");
//Display the value
System.out.println("Old value: " +oldString);
System.out.println("New value: " +atomicReference.get());
}
}
Output:
Old value: Old String of atomic reference
New value: New String of atomic reference
Example 3
The example below illustrates the Atomic reference usage in a thread-based environment.
FileName: AtomicReferenceTest2.java
//Import the required package
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest2 {
private static String str = "I am Learning Java!";
private static AtomicReference<String> reference;
// main method
public static void main(String[] args) {
// creates an atomic reference
reference = new AtomicReference<>(str);
// Creates a Thread
new Thread("My Thread") {
@Override
public void run() {
reference.compareAndSet(str,"Thread No:1");
}
}.start();
//Display the value
System.out.println("The String is: " +str);
System.out.println(reference.get());
}
}
Output:
The String is: I am Learning Java!
Thread No:1
Conclusion
Using volatile variables in Java can lead to race conditions as a particular thread interleaving for a thread can overwrite the computations by some other threads. This problem can be avoided using the compareAndSet() function from the atomic reference class. Here, we atomically check if the current value is the same or equal to the older one. If it is similar, then the present value can be updated securely. Note that it uses the == comparison and not the equals() method to check for equality of expected value.