Tuesday, 6 September 2016

AtomicLong in Java Concurrency

AtomicLong class provides a long value that may be updated atomically. This class resides in the java.util.concurrent.atomic package which has classes that support lock-free thread-safe programming on single variables. Apart from AtomicLong some of the other classes are AtomicInteger, AtomicReference, DoubleAccumulator.

The atomic variable classes in Java concurrency like AtomicLong, AtomicInteger use non-blocking algorithm. These non-blocking algorithms use low-level atomic machine instructions such as compare-and-swap instead of locks to ensure data integrity under concurrent access.

Classes in this package java.util.concurrent.atomic provides methods that can get, set or compare value as an atomic operation i.e. without any interruption. There is no need to explicitly use any locking or  synchronization.

AtomicLong Constructor

AtomicInteger class has two constructors -

  • AtomicLong() - Creates a new AtomicLong with initial value 0.
  • AtomicLong(long initialValue) - Creates a new AtomicLong with the given initial value.

Atomic operations

AtomicLong class provides atomic methods for getting, setting, incrementing and decrementing variables like getAndIncrement(), getAndDecrement(), decrementAndGet(), getAndSet(), getAndAdd() etc.

From the method names itself you can easily deduce that these are atomic methods as example if you take getAndIncrement() method which is doing three operatios.

Gets the value
Increment the value by 1
Sets the updated value back

But these 3 operations are done as a single unit i.e. atomic operation. Either all 3 succeed or none.

There is also a compareAndSet(int expect, int update) method which atomically sets the value to the given updated value if the current value == the expected value.

Example Code

Let us see some examples using AtomingLong.

Adding to the AtomicLong

Some of the methods that can be used for adding are

  • addAndGet(long delta) - Atomically adds the given value to the current value. Returns the updated value.
  • getAndAdd(long delta) - Atomically adds the given value to the current value. Returns the previous value.
  • incrementAndGet() - Atomically increments the current value by one. Returns the updated value.
  • getAndIncrement() - Atomically increments by one the current value. Returns the previous value.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

public class AtomicLongDemo {

 public static void main(String[] args) {
  AtomicLong al = new AtomicLong();
  ExecutorService ex = Executors.newFixedThreadPool(2);
  ex.execute(new IncTask(al));
  ex.execute(new IncTask(al));
  ex.execute(new IncTask(al));
  ex.execute(new IncTask(al));

 }

}

class IncTask implements Runnable{
 AtomicLong al = null;
 IncTask(AtomicLong al){
  this.al = al;
 }
 
 @Override
 public void run() {
  System.out.println("Value - " + al.getAndIncrement() + " for " + Thread.currentThread().getName()); 
 }
 
}

Output

Value - 1 for pool-1-thread-2
Value - 0 for pool-1-thread-1
Value - 2 for pool-1-thread-2
Value - 3 for pool-1-thread-1

In this code if you notice there is no synchronization or ReentrantLock is used still values are different for different threads as AtomicLong is used. You can change AtomicLong to just Long and see how the same program behaves.

addAndGet and getAndAdd() methods

As already mentioned addAndGet() method returns the updated value whereas getAndAdd() returns the previous value.

import java.util.concurrent.atomic.AtomicLong;

public class AddAtomicLong {

 public static void main(String[] args) {
  AtomicLong al = new AtomicLong();
  System.out.println("Value after addAndGet - " + al.addAndGet(7));
  System.out.println("Value after getAndAdd - " + al.getAndAdd(7));
  System.out.println("Current Value - " + al.get());
 }
}

Output

Value after addAndGet - 7
Value after getAndAdd - 7
Current Value - 14

compareAndSet() method

compareAndSet(long expect, long update) - Atomically sets the value to the given updated value if the current value == the expected value.
Returns - true if successful. False return indicates that the actual value was not equal to the expected value.

Example code

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

public class AddAtomicLong {

 public static void main(String[] args) {
  AtomicLong al = new AtomicLong(7);
  ExecutorService ex = Executors.newFixedThreadPool(2);
  ex.execute(new CompareTask(al));
  ex.execute(new CompareTask(al));
  ex.execute(new CompareTask(al));
  ex.execute(new CompareTask(al));
  ex.shutdown();
  System.out.println("Current Value " + al.get());

 }

}

class CompareTask implements Runnable{
 AtomicLong al = null;
 CompareTask(AtomicLong al){
  this.al = al;
 }
 
 @Override
 public void run() {
  System.out.println("Value - " + al.compareAndSet(7, 3) + " for " + Thread.currentThread().getName()); 
 }
 
}

Output

Current Value 3
Value - true for pool-1-thread-1
Value - false for pool-1-thread-2
Value - false for pool-1-thread-1
Value - false for pool-1-thread-2

Here it can be seen that when compareAndSet() method is called for these 4 threads, only one thread will be able to set the value to 3. After that all the other will return false as expected value becomes 3.

That's all for this topic AtomicLong in Java Concurrency. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. AtomicInteger in Java Concurrency
  2. Non-blocking algorithms
  3. Lock Striping in Java Concurrency
  4. Blocking methods in Java Concurrency
  5. Java Concurrency interview questions

You may also like -

2 comments:

  1. I did not hear about atomic variable classes before. Thanks for sharing.

    ReplyDelete
  2. Glad to know that it was me who introduced you to Atomic variables :) ..

    ReplyDelete