Monday, December 23, 2013

Java Atomic Operations – AtomicInteger Example

Atomic operations are performed in a single unit of task without interference from other operations. Atomic operations are necessity in multi-threaded environment to avoid data inconsistency.

Let’s create a simple multi-threaded program where every thread increments the shared count variable 4 times. So if there are two threads, after they finish count value should be 8.

JavaAtomic.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

packagecom.journaldev.concurrency;

publicclassJavaAtomic {

publicstaticvoidmain(String[] args) throwsInterruptedException {

ProcessingThread pt = newProcessingThread();

Thread t1 = newThread(pt, "t1");

t1.start();

Thread t2 = newThread(pt, "t2");

t2.start();

t1.join();

t2.join();

System.out.println("Processing count="+ pt.getCount());

}

}

classProcessingThread implementsRunnable {

privateintcount;

@Override

publicvoidrun() {

for(inti = 1; i < 5; i++) {

processSomething(i);

count++;

}

}

publicintgetCount() {

returnthis.count;

}

privatevoidprocessSomething(inti) {

// processing some job

try{

Thread.sleep(i * 1000);

} catch(InterruptedException e) {

e.printStackTrace();

}

}

}

If you will run above program, you will notice that count value varies between 5,6,7,8. The reason is because count++ is not an atomic operation. So by the time one threads read it’s value and increment it by one, other thread has read the older value leading to wrong result.

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

Here is the updated program that will always output count value as 8 because AtomicIntegerincrementAndGet() atomically increments the current value by one.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

packagecom.journaldev.concurrency;

importjava.util.concurrent.atomic.AtomicInteger;

publicclassJavaAtomic {

publicstaticvoidmain(String[] args) throwsInterruptedException {

ProcessingThread pt = newProcessingThread();

Thread t1 = newThread(pt, "t1");

t1.start();

Thread t2 = newThread(pt, "t2");

t2.start();

t1.join();

t2.join();

System.out.println("Processing count="+ pt.getCount());

}

}

classProcessingThread implementsRunnable {

privateAtomicInteger count = newAtomicInteger();

@Override

publicvoidrun() {

for(inti = 1; i < 5; i++) {

processSomething(i);

count.incrementAndGet();

}

}

publicintgetCount() {

returnthis.count.get();

}

privatevoidprocessSomething(inti) {

// processing some job

try{

Thread.sleep(i * 1000);

} catch(InterruptedException e) {

e.printStackTrace();

}

}

}

Benefits of using Atomic Concurrency classes is that we don’t need to worry about synchronization at each and every place we are dealing with integers and it’s assumed to be more efficient that synchronization which involves locking resources.