AtomicInteger vs Integer and how is AtomicInteger implemented

The AtomicInteger class provides you with a int variable which can be read and written atomically, and which also contains advanced atomic operations like compareAndSet().

Consider this non-thread safe program :

package threads;
 
import java.util.concurrent.atomic.AtomicInteger;
 
public class AtomicIntegerExample {
 
   	 static Integer sharedAtomicInteger =new Integer(0);
 
   	public static void main(String...args) throws InterruptedException{
          	MyRunnable runnable=new MyRunnable();
          	Thread thread1=new Thread(runnable,"Thread-1");
          	Thread thread2=new Thread(runnable,"Thread-2");
          	thread1.start();
          	thread2.start();
 
          	Thread.sleep(1000); //delay to ensure Thread-1 and Thread-2 finish
        System.out.println("After completion of both threads, "
                   	+ "sharedAtomicInteger = "+sharedAtomicInteger);
   	}
}
 
 
 
 
class MyRunnable implements Runnable{
 
   	public void run(){
          	for(int i=0;i<2;i++){ System.out.println("ThreadName="+Thread.currentThread().getName() +" > "+ AtomicIntegerExample.sharedAtomicInteger++);
 
          	}         	
 
   	}
}

Running this multiple times will give either of these outputs :

ThreadName=Thread-1 > 0
ThreadName=Thread-2 > 0
ThreadName=Thread-1 > 1
ThreadName=Thread-2 > 2
After completion of both threads, sharedAtomicInteger = 3

or

ThreadName=Thread-1 > 0
ThreadName=Thread-2 > 1
ThreadName=Thread-1 > 2
ThreadName=Thread-2 > 3
After completion of both threads, sharedAtomicInteger = 4

So we can see as the variable was not safe and multiple threads were trying to change its value, we are getting inconsistent results

Now let’s replace the Integer with Atomicinteger

package threads;
 
import java.util.concurrent.atomic.AtomicInteger;
 
public class AtomicIntegerExample {
 
   	//Create a new AtomicIntegerCustom and is initialized with 0.
   	static AtomicInteger sharedAtomicInteger =new AtomicInteger();
 
   	public static void main(String...args) throws InterruptedException{
          	MyRunnable runnable=new MyRunnable();
          	Thread thread1=new Thread(runnable,"Thread-1");
          	Thread thread2=new Thread(runnable,"Thread-2");
          	thread1.start();
          	thread2.start();
 
          	Thread.sleep(1000); //delay to ensure Thread-1 and Thread-2 finish
        	System.out.println("After completion of both threads, "
                   	+ "sharedAtomicInteger = "+sharedAtomicInteger);
   	}
}
 
 
 
 
class MyRunnable implements Runnable{
 
   	public void run(){
          	for(int i=0;i<2;i++){ System.out.println("ThreadName="+Thread.currentThread().getName() +" > "+
	   	AtomicIntegerExample.sharedAtomicInteger.incrementAndGet());
          	}         	
 
   	}
}

Run this code any number of times, output will always be :

ThreadName=Thread-1 > 2
ThreadName=Thread-2 > 1
ThreadName=Thread-2 > 3
ThreadName=Thread-1 > 4
After completion of both threads, sharedAtomicInteger = 4

The classes that support atomic operations e.g. AtomicInteger, AtomicLong etc. makes use of CAS. CAS does not make use of locking rather it is very optimistic in nature. It follows these steps:

Compare the value of the primitive to the value we have got in hand.
If the values do not match it means some thread in between has changed the value. Else it will go ahead and swap the value with new value.
Check the following code in AtomicLong class:

public final long incrementAndGet() {
    for (;;) {
        long current = get();
        long next = current + 1;
        if (compareAndSet(current, next))
          return next;
    }
}

Uday Ogra

Connect with me at http://facebook.com/tendulkarogra and lets have some healthy discussion :)

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *