Java Atomic Operations And Nonblocking Algorithms Tutorial With Examples

Atomic operation

An operation during which a processor can simultaneously read a location and write it in the same bus operation. This prevents any other processor or I/O device from writing or reading memory until the operation is complete.

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.
For example, the following code is thread safe:
 
public class Counter
{
    private int x = 0;
    public void value()
    {
         return x;
    }
}
However, we should be careful to note that the guarentee 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.
Since Java 1.5 the java language provides atomic variables, e.g. AtomicIntegeror, AtomicLong which provide methods like getAndDecrement(), getAndIncrement() and getAndSet() which are atomic.

Atomic Variables

The java.util.concurrent.atomic package defines classes that support atomic operations on single variables. All classes have get and set methods that work like reads and writes on volatile variables. That is, a set has a happens-before relationship with any subsequent get on the same variable. The atomic compareAndSet method also has these memory consistency features, as do the simple atomic arithmetic methods that apply to integer atomic variables. To see how this package might be used, let's return to the Counter class:
 
public class Counter
{
    private int x = 0;

    public void increment()
    {
        ++this.value;
    }
    public void decrement()
    {
        --this.value;
    }
    public void value()
    {
         return x;
    }
}
One way to make Counter safe from thread interference is to make its methods synchronized, as in SynchronizedCounter:

 
public class SynchronizedCounter 
{
    private int x = 0;

    public synchronized  void increment()
    {
        ++this.value;
    }
    public synchronized  void decrement()
    {
        --this.value;
    }
    public synchronized  int value()
    {
         return x;
    }
}

For this simple class, synchronization is an acceptable solution. Now Counter is thread-safe, but the need to use a lock irks some developers because of the performance cost involved.

Nonblocking algorithms

Java 5.0 provides supports for additional atomic operations. This allows to develop algorithm which are non-blocking algorithm, e.g. which do not require synchronization, but are based on low-level atomic hardware primitives such as compare-and-swap (CAS). A compare-and-swap operation check if the variable has a certain value and if it has this value it will perform this operation.
Non-blocking algorithm are usually much faster then blocking algorithms as the synchronization of threads appears on a much finer level (hardware).

import java.util.concurrent.atomic.AtomicInteger;

class AtomicCounter {
    private AtomicInteger c = new AtomicInteger(0);

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

    public void decrement() {
        c.decrementAndGet();
    }

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

}

java.util.concurrent.atomic package

All java.util.concurrent.atomic package classes have the "atomic" prefix in their names. There are different types of atomic variables available in the java.util.concurrent.atomic package, including:
  • AtomicBoolean
  • AtomicInteger
  • AtomicIntegerArray
  • AtomicIntegerFieldUpdater
  • AtomicLong
  • AtomicLongArray
  • AtomicLongFieldUpdater
  • AtomicReference
In the Java language, synchronization coordinates access to shared thread fields and only allows threads holding locks to access and modify variables protected by the lock. This thread’s modifications are visible to the thread that follows, but only after the thread releases the lock. An example is a scenario where thread A holds a lock. A is only able to access and make changes to variables protected by this lock. If thread B holds this lock after A, then only B can view A’s changes on the variables protected by that particular lock. The main problem with locking occurs when B attempts to acquire a lock held by A. In this case, B is blocked to wait until the lock is available. Nonblocking algorithms resolve this problem.
The main purpose behind building atomic classes is to implement nonblocking data structures and their related infrastructure classes. Atomic classes do not serve as replacements for java.lang.Integer and related classes. Most java.util.concurrent package classes use atomic variables instead of synchronization, either directly or indirectly. Atomic variables also are used to achieve higher throughput, which means higher application server performance.

Hope we are able to explain you java Atomic Operations, if you have any questions or suggestions please write to us using contact us form.(Second Menu from top left).

Please share us on social media if you like the tutorial.
SHARE
    Blogger Comment
    Facebook Comment