AtomicLongArray

java.util.concurrent.atomic.AtomicLongArray Example

In this example we shall show you how to make use of AtomicLongArray class,  AtomicLongArray is a long array in which elements may be updated atomically. In a multithreading concurrent application architecture, we have a few tasks which are parallelized in such a way as to require no coordination between threads. The true problem comes when we need a coordination between those threads. For example, consider a thread pool, where the tasks being executed are generally independent of each other. If the thread pool feeds off a common work queue, then the process of removing elements from or adding elements to the work queue must be thread-safe, and that means coordinating access to the head, tail, or inter-node link pointers. And it is this coordination that causes all the trouble.

 

1. What is the best solution?

1.1. Locking:

Synchronization is the traditional way to coordinate access to shared fields in the Java language where we assured that whichever thread holds the lock that protects a given set of variables will have exclusive access to those variables, and changes to those variables will become visible to other threads when they subsequently acquire the lock. However, Synchronization comes with cost of performance where threads frequently ask to acquire the lock when it is already held by another thread.

1.2. Volatile:

Volatile variables can also be used to store shared variables at a lower cost than that of Synchronization, but they have limitations. While writes to volatile variables are guaranteed to be immediately visible to other threads, there is no way to render a read-modify-write sequence of operations atomic because of accessing a volatile variable never holds a lock, it is not suitable for cases where we want to read-update-write as an atomic operation (unless we’re prepared to “miss an update”).

The Synchronization (Locking) guarantees visibility and atomicity with a performance cost and Volatile guarantees visibility and not the atomicity. So, what is the best solution?

1.3. Atomic classes:

With the release of Java SE 5, Sun included a java.util.concurrent.atomic package that addresses this limitation. And specifically they added these classes (AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean; array forms of atomic integer; long; reference; and atomic marked reference and stamped reference classes, which atomically update a pair of values).

Let’s see AtomicLongArray as an example of those classes.

2. Example:

In this example, we will use two method of  AtomicLongArray (getAndIncrement(int i), getAndDecrement(int i))  to update the given AtomicLongArray.

IncrementUpdateTask class is a Runnable task which increment each element in the given AtomicLongArray by one.

2.1. IncrementUpdateTask.java:

package com.jcg;

import java.util.concurrent.atomic.AtomicLongArray;

/**
 * @author ashraf
 *
 */
public class IncrementUpdateTask implements Runnable {
	
	private AtomicLongArray atomicLongArray;

	public IncrementUpdateTask(AtomicLongArray atomicLongArray) {
		super();
		this.atomicLongArray = atomicLongArray;
	}

	public void run() {

		try {
			for (int i = 0; i < atomicLongArray.length(); i++) {
				System.out.println("Increment element "+ i +" by 1");
				atomicLongArray.getAndIncrement(i);
				Thread.sleep(1000);
			}
		} catch (InterruptedException ie) {
			ie.printStackTrace();

		} finally {
			System.out.println("Increment task was done !!!");
		}
	}

}

DecrementUpdateTask class is a Runnable task which decrement each element in the given AtomicLongArray by one.

2.2. DecrementUpdateTask.java:

package com.jcg;

import java.util.concurrent.atomic.AtomicLongArray;

/**
 * @author ashraf
 *
 */
public class DecrementUpdateTask implements Runnable {
	
	private AtomicLongArray atomicLongArray;

	public DecrementUpdateTask(AtomicLongArray atomicLongArray) {
		super();
		this.atomicLongArray = atomicLongArray;
	}

	public void run() {

		try {
			for (int i = 0; i < atomicLongArray.length(); i++) {
				System.out.println("Decrement element" + i +" by 1");
				atomicLongArray.getAndDecrement(i);
				Thread.sleep(1000);
			}
		} catch (InterruptedException ie) {
			ie.printStackTrace();

		} finally {
			System.out.println("Decrement task was done !!!");
		}
	}

}

AtomicLongArrayDemo class creates a new AtomicLongArray with the predefined long array of 10 elements, then it creates a new ExecutorService with 2 thread, After that it creates two Future tasks to increment and decrement AtomicLongArray at the same time.

2.3. AtomicLongArrayDemo.java:

package com.jcg;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLongArray;

/**
 * @author ashraf
 *
 */
public class AtomicLongArrayDemo {

	private static final int ARRAY_SIZE = 10;

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		// Create a new long array of 10 element
		long[] longArray = new long[ARRAY_SIZE];
		for (int i = 0; i < ARRAY_SIZE; i++) {
			longArray[i] = i + 1;
		}

		// Create a new AtomicLongArray with the predefined long array
		AtomicLongArray atomicLongArray = new AtomicLongArray(longArray);

		System.out.println("atomicLongArray before running tasks:\n"
				+ atomicLongArray);

		System.out.println("Start running increment/decrement tasks ...");
		// Create a new ExecutorService with 2 thread to Increment and Decrement
		// AtomicLongArray
		ExecutorService executor = Executors.newFixedThreadPool(2);

		// Start AtomicLongArray increment task
		Future futureIncrementTask = executor
				.submit(new IncrementUpdateTask(atomicLongArray));

		// Start AtomicLongArray Decrement task
		Future futureDecrementTask = executor
				.submit(new DecrementUpdateTask(atomicLongArray));

		while (true) {

			if (futureIncrementTask.isDone() && futureDecrementTask.isDone()) {
				System.out
				.println("Finish running increment/decrement tasks !!!");
				System.out.println("atomicLongArray after running tasks:\n"
						+ atomicLongArray);
				executor.shutdown();
				break;
			}
		}

	}

}

As we notice that the AtomicLongArray wasn’t changed after we running the increment and decrement tasks because the AtomicLongArray manages the updating process very well where each thread update is visible and atomic to the other thread. So, whenever the increment task update an element, this update immediately becomes visible and atomic to the decrement task which reverse this update.

2.4. Output:

atomicLongArray before running tasks:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Start running increment/decrement tasks ...
Increment element 0 by 1
Decrement element0 by 1
Increment element 1 by 1
Decrement element1 by 1
Increment element 2 by 1
Decrement element2 by 1
Increment element 3 by 1
Decrement element3 by 1
Increment element 4 by 1
Decrement element4 by 1
Increment element 5 by 1
Decrement element5 by 1
Increment element 6 by 1
Decrement element6 by 1
Increment element 7 by 1
Decrement element7 by 1
Increment element 8 by 1
Decrement element8 by 1
Increment element 9 by 1
Decrement element9 by 1
Increment task was done !!!
Decrement task was done !!!
Finish running increment/decrement tasks !!!
atomicLongArray after running tasks:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

3. Download the Source Code of this example:

This was an example of how to use AtomicLongArray.

Download
You can download the full source code of this example here: AtomicLongArrayExampleCode.zip

Ashraf Sarhan

Ashraf Sarhan is a passionate software engineer, an open source enthusiast, has a Bsc. degree in Computer and Information Systems from Alexandria University. He is experienced in building large, scalable and distributed enterprise applications/service in multiple domains. He also has a keen interest in JavaEE, SOA, Agile and Big Data technologies.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button