Thursday, 3 April 2014

How to avoid thread collision using AtomicInteger java?

Each of the method discussed here  has some advantages and disadvantages.  Here we will see the java.util.concurrent.atomic package.

java.util.concurrent.atomic package:


This package has the following classes. The API says this package as, "A small toolkit of classes that support lock-free thread-safe programming on single variables."

  • AtomicBoolean

  • AtomicInteger

  • AtomicIntegerArray

  • AtomicIntegerFieldUpdater<T>

  • AtomicLong

  • AtomicLongArray

  • AtomicLongFieldUpdater<T>

  • AtomicMarkableReference<V>

  • AtomicReference<V>

  • AtomicReferenceArray<E>

  • AtomicReferenceFieldUpdater<T,V>

  • AtomicStampedReference<V>


Advantages:


Using these classes thread does not require lock on the object. This avoids the waiting time to get the lock. (Locks will be explained further)

Disadvantages:


These classes can be used with only variables, but not with the classes or methods.

I will discuss about the AtomicInteger class here.

AtomicInteger:


AtomicInteger class has some thread safe methods by which it ensures that atomic operations will be executed by a single thread only.
Please see the below program for better understanding.
package thread;

import java.util.concurrent.atomic.AtomicInteger;

/**
* @author Sivaranjani D
*
*/
public class AtomicIntegerExample {
public static void main(String args[]) {

Incrementer job = new Incrementer();
Thread t1 = new Thread(job);
Thread t2 = new Thread(job);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("Normal " + job.getIncerementedNumber());
System.out.println("Atomic " + job.getIncerementedAtomicNumber());
}
}

class Incrementer implements Runnable {
AtomicInteger atomicnumber = new AtomicInteger();
int normalnumber = 0;

public void run() {
for (int i = 0; i < 50; i++) {
increment();
incrementAtomicNumber();
}
}

public int getIncerementedNumber() {
return normalnumber;
}

public void increment() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
normalnumber++;
}

public AtomicInteger getIncerementedAtomicNumber() {
return atomicnumber;
}

public void incrementAtomicNumber() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicnumber.addAndGet(1);

}
}

Explanation:

  1. Incrementer class implements Runnable and it has 2 fields namely normalnumber  of type int and a atomicnumber of type AtomicInteger .

  2. There are 2 methods namely increment which increments the normalnumber  and incrementAtomicNumber which increments the atomicnumber 

  3. And we are calling the above 2 methods in the run method of Incrementer for 50 times .

  4. We are creating 2 threads in the AtomicIntegerExample  class by passing the above Incrementer c lass Object.

  5. Now both the threads should execute the run method of Incrementer class and loops it for 50 times.

  6. Since we made t1.join() and t2.join(), main Thread will waits on the both the thread

  7. After both the threads complets, main thread will print the value.

  8. The output will be always 50 for the atomicnumber , but when you take the normalnumber it is not. That is because, AtomicInteger does the following 3 tasks (atomic) in a single block but normalnumber does not.



  • Read the old value of normalnumber

  • Increment the normalnumber

  • Reassign the incremented value to normalnumber

No comments:

Post a Comment