In this tutorial we will see basic use of AtomicBoolean, AtomicInteger and AtomicLong. Each of this classes provide access and updates to a single variable of the corresponding type.
AtomicBoolean Example
This class wraps boolean value to be updated atomically. In this example we want to lazily initialize some code only once. The initializing method is accessed by multiple threads.
Without AtomicBoolean
package com.logicbig.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class NonAtomicBooleanExample {
private static boolean init;
public static void init() {
if (!init) {
System.out.println("initializing");
//initialize some expensive stuff
init = true;
}
}
public static void main(String[] args) throws InterruptedException {
int c = 10;
ExecutorService es = Executors.newFixedThreadPool(c);
for (int i = 0; i < c; i++) {
es.execute(NonAtomicBooleanExample::init);
}
es.shutdown();
es.awaitTermination(10, TimeUnit.MINUTES);
}
}
initializing initializing initializing initializing initializing
The problem with above code is, the two actions i.e. reading boolean variable 'init' and changing it's value to true, are not atomic.
With AtomicBoolean
Let's fix above code by replacing boolean with AtomicBoolean
package com.logicbig.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class AtomicBooleanExample {
private static AtomicBoolean init = new AtomicBoolean();
public static void init() {
if (init.compareAndSet(false, true)) {
System.out.println("initializing");
//initialize some expensive stuff
}
}
public static void main(String[] args) throws InterruptedException {
int c = 10;
ExecutorService es = Executors.newFixedThreadPool(c);
for (int i = 0; i < c; i++) {
es.execute(AtomicBooleanExample::init);
}
es.shutdown();
es.awaitTermination(10, TimeUnit.MINUTES);
}
}
initializing
AtomicInteger Example
without AtomicInteger
package com.logicbig.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class NonAtomicIntegerExample {
private static int num;
public static void main(String[] args) throws InterruptedException {
for (int k = 0; k < 10; k++) {
num = 0;
ExecutorService es = Executors.newFixedThreadPool(2);
es.execute(() -> {
for (int i = 0; i < 10000; i++) {
num++;
}
});
es.execute(() -> {
for (int i = 0; i < 10000; i++) {
num++;
}
});
es.shutdown();
es.awaitTermination(10, TimeUnit.MINUTES);
System.out.println(num);
}
}
}
20000 13821 13425 12734 11173 12842 11961 20000 20000 18467
In above example the total sum is not always 2000, that's because the increment operation num++ is not atomic (as we saw here).
With AtomicInteger
package com.logicbig.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerExample {
private static AtomicInteger num = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
for (int k = 0; k < 10; k++) {
num.set(0);
ExecutorService es = Executors.newFixedThreadPool(2);
es.execute(() -> {
for (int i = 0; i < 10000; i++) {
num.incrementAndGet();
}
});
es.execute(() -> {
for (int i = 0; i < 10000; i++) {
num.incrementAndGet();
}
});
es.shutdown();
es.awaitTermination(10, TimeUnit.MINUTES);
System.out.println(num.get());
}
}
}
20000 20000 20000 20000 20000 20000 20000 20000 20000 20000
AtomicLong
It is very similar to AtomicInteger and wraps a long variable atomically.
Without AtomicLong
package com.logicbig.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class NonAtomicLongExample {
private static long sum;
public static void main(String[] args) throws InterruptedException {
for (int k = 0; k < 5; k++) {
sum = 0;
ExecutorService es = Executors.newFixedThreadPool(50);
for (int i = 1; i <= 50; i++) {
int finalI = i;
es.execute(() -> {
sum += Math.pow(2, finalI);
});
}
es.shutdown();
es.awaitTermination(10, TimeUnit.MINUTES);
System.out.println(sum);
}
}
}
2251799813685244 2251799813685246 2251799813685246 2251799813685182 2251799813685246
The sum of 2^1+2^2+2^3.....2^50 should always be 2251799813685246.
With AtomicLong
package com.logicbig.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class AtomicLongExample {
private static AtomicLong sum = new AtomicLong();
public static void main(String[] args) throws InterruptedException {
for (int k = 0; k < 5; k++) {
sum.set(0);
ExecutorService es = Executors.newFixedThreadPool(50);
for (int i = 1; i <= 50; i++) {
int finalI = i;
es.execute(() -> {
sum.addAndGet((long) Math.pow(2, finalI));
});
}
es.shutdown();
es.awaitTermination(10, TimeUnit.MINUTES);
System.out.println(sum);
}
}
}
2251799813685246 2251799813685246 2251799813685246 2251799813685246 2251799813685246
Example ProjectDependencies and Technologies Used:
|