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.
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
| package com.journaldev.concurrency; public class JavaAtomic { public static void main(String[] args) throws InterruptedException { ProcessingThread pt = new ProcessingThread(); Thread t1 = new Thread(pt, "t1" ); t1.start(); Thread t2 = new Thread(pt, "t2" ); t2.start(); t1.join(); t2.join(); System.out.println( "Processing count=" + pt.getCount()); } } class ProcessingThread implements Runnable { private int count; @Override public void run() { for ( int i = 1 ; i < 5 ; i++) { processSomething(i); count++; } } public int getCount() { return this .count; } private void processSomething( int i) { // 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
| package com.journaldev.concurrency; import java.util.concurrent.atomic.AtomicInteger; public class JavaAtomic { public static void main(String[] args) throws InterruptedException { ProcessingThread pt = new ProcessingThread(); Thread t1 = new Thread(pt, "t1" ); t1.start(); Thread t2 = new Thread(pt, "t2" ); t2.start(); t1.join(); t2.join(); System.out.println( "Processing count=" + pt.getCount()); } } class ProcessingThread implements Runnable { private AtomicInteger count = new AtomicInteger(); @Override public void run() { for ( int i = 1 ; i < 5 ; i++) { processSomething(i); count.incrementAndGet(); } } public int getCount() { return this .count.get(); } private void processSomething( int i) { // 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.
No comments:
Post a Comment