Friday, 7 April 2017

Atomic Variables

Run below program and notice that count value varies between 9, 10, 11 to 18. The reason is because count++ is not an atomic operation. So by the time one threads read its value and increment it by one, other thread has read the older value leading to wrong result.

class Worker implements Runnable {
     private int count;

     @Override
     public void run() {
           for (int i = 1; i < 10; i++) {
                process(i);
                count++;
           }
     }

     public int getCount() {
           return this.count;
     }

     private void process(int i) {
           try {
                Thread.sleep(i * 200);
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
     }
}

public class TestThreads {
     public static void main(String[] args) throws InterruptedException {
           Worker pt = new Worker();
          
           Thread t1 = new Thread(pt, "t1");
           t1.start();
           Thread t2 = new Thread(pt, "t2");
           t2.start();
           t1.join();
           t2.join();
           System.out.println("Count=" + pt.getCount());
     }
}

To solve this issue, we will have to make sure that increment operation on count is atomic, we can do that using Synchronization however Java 5 java.util.concurrent.atomic provides wrapper classes for int and long that can be used to achieve this atomic operation without usage of Synchronization.

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 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.

import java.util.concurrent.atomic.AtomicInteger;
class Worker implements Runnable {
     private AtomicInteger count = new AtomicInteger();

     @Override
     public void run() {
           for (int i = 1; i < 10; i++) {
                process(i);
                count.incrementAndGet();
           }
     }

     public int getCount() {
           return this.count.get();
     }

     private void process(int i) {
           try {
                Thread.sleep(i * 200);
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
     }
}


No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...