After my post ‘ThreadLocal, what is it?’ I would write some words about the java.util.concurrent.atomic package that contains a small toolkit of classes supporting lock-free thread-safe programming on single variables.
We will compare in this example the 3 types of shared counters:
– a simple counter without synchronization or lock,
– an advanced counter with synchronization,
– an atomic counter without synchronization or lock but with AtomicInteger,
Here, a classe defining 3 static counters accessed by several threads:
public class MyValueData { // Counter n°1 private Integer counterSimple = new Integer(0); // Counter n°2 private Integer counterAdvanced = new Integer(0); // Counter n°3 private AtomicInteger counterAtomic = new AtomicInteger(0); public MyValueData(){ } public synchronized Integer getCounterAdvanced() { return counterAdvanced; } public Integer getCounterSimple() { return counterSimple; } public Integer getCounterAtomic() { return counterAtomic.get(); } public void incrementCounterSimple() { this.counterSimple++; } public synchronized void incrementCounterAdvanced() { this.counterAdvanced++; } public void incrementCounterAtomic() { this.counterAtomic.getAndIncrement(); } }
Then, we define a Runnable which:
1- starts and sleeps during a 1100ms,
2- increments the 3 counters,
3- repeats the steps 1 and 2 until the counter n°1 is equal or greater than 100;
public class MyTask implements Runnable { private int sleepTime; // random sleep time for thread private String threadName; // name of thread private MyValueData myValueData; public MyTask(String name, MyValueData myValueData) { // set name of thread this.threadName = name; this.sleepTime = 1100; this.myValueData = myValueData; } public void run() { try{ while(this.myValueData.getCounterAdvanced()<100){ // put thread to sleep for sleepTime amount of time System.out.printf("%s with sleep for %d ms: counterSimple=%d, counterAdvanced=%d, counterAtomic=%d, \n", this.threadName, this.sleepTime, this.myValueData.getCounterSimple(), this.myValueData.getCounterAdvanced(), this.myValueData.getCounterAtomic()); // put thread to sleep Thread.sleep( this.sleepTime ); // // Increment this.myValueData.incrementCounterSimple(); this.myValueData.incrementCounterAtomic(); this.myValueData.incrementCounterAdvanced(); } } catch ( InterruptedException exception ) { exception.printStackTrace(); } // print thread name System.out.printf( "%s done sleeping\n", this.threadName ); } }
At last, the main method which will:
– create a instance of ‘MyValueData’ class containing the 3 counters,
– create 3 threads named “threadname_1″, “threadname_2″ and “threadname_3″ with the above instance of ‘MyValueData’,
– execute these 3 threads due to an ExecutorService;
public static void main(String[] args) { // create and name each runnable MyValueData myValueData = new MyValueData(); MyTask th1 = new MyTask("threadname_1", myValueData); MyTask th2 = new MyTask("threadname_2", myValueData); MyTask th3 = new MyTask("threadname_3", myValueData); // create ExecutorService to manage threads OR empty (better) ExecutorService es = Executors.newFixedThreadPool(3); // start threads and place in runnable state es.execute(th1); es.execute(th2); es.execute(th3); // shutdown worker threads es.shutdown(); }
…so the ouputs in console would be like the following traces. In these outputs, we could see that the counter n°2 (advanced counter with synchronization) and counter n°3 (atomic counter without synchronization or lock but with AtomicInteger) have the same values corresponding to the number of occurrences done. However, the counter n°1 (simple counter without synchronization or lock) has a different value from the two others because this counter is not protected by a synchronization or lock system.
At the end, the value of these counters are:
– threadname_1 with sleep for 1100 ms: counterSimple=97, counterAdvanced=99, counterAtomic=99,
– threadname_2 with sleep for 1100 ms: counterSimple=96, counterAdvanced=98, counterAtomic=98,
– threadname_3 with sleep for 1100 ms: counterSimple=95, counterAdvanced=97, counterAtomic=97,
threadname_2 with sleep for 1100 ms: counterSimple=0, counterAdvanced=0, counterAtomic=0, threadname_3 with sleep for 1100 ms: counterSimple=0, counterAdvanced=0, counterAtomic=0, threadname_1 with sleep for 1100 ms: counterSimple=0, counterAdvanced=0, counterAtomic=0, threadname_3 with sleep for 1100 ms: counterSimple=2, counterAdvanced=1, counterAtomic=2, threadname_1 with sleep for 1100 ms: counterSimple=3, counterAdvanced=3, counterAtomic=3, threadname_2 with sleep for 1100 ms: counterSimple=2, counterAdvanced=2, counterAtomic=2, threadname_1 with sleep for 1100 ms: counterSimple=4, counterAdvanced=4, counterAtomic=4, threadname_3 with sleep for 1100 ms: counterSimple=6, counterAdvanced=6, counterAtomic=6, threadname_2 with sleep for 1100 ms: counterSimple=5, counterAdvanced=5, counterAtomic=5, threadname_3 with sleep for 1100 ms: counterSimple=7, counterAdvanced=7, counterAtomic=7, threadname_1 with sleep for 1100 ms: counterSimple=9, counterAdvanced=9, counterAtomic=9, threadname_2 with sleep for 1100 ms: counterSimple=8, counterAdvanced=8, counterAtomic=8, threadname_2 with sleep for 1100 ms: counterSimple=10, counterAdvanced=10, counterAtomic=10, threadname_1 with sleep for 1100 ms: counterSimple=11, counterAdvanced=11, counterAtomic=11, threadname_3 with sleep for 1100 ms: counterSimple=12, counterAdvanced=12, counterAtomic=12, threadname_2 with sleep for 1100 ms: counterSimple=13, counterAdvanced=13, counterAtomic=13, threadname_3 with sleep for 1100 ms: counterSimple=14, counterAdvanced=14, counterAtomic=14, threadname_1 with sleep for 1100 ms: counterSimple=15, counterAdvanced=15, counterAtomic=15, threadname_1 with sleep for 1100 ms: counterSimple=16, counterAdvanced=16, counterAtomic=16, threadname_3 with sleep for 1100 ms: counterSimple=18, counterAdvanced=18, counterAtomic=18, threadname_2 with sleep for 1100 ms: counterSimple=17, counterAdvanced=17, counterAtomic=17, threadname_1 with sleep for 1100 ms: counterSimple=19, counterAdvanced=19, counterAtomic=19, threadname_3 with sleep for 1100 ms: counterSimple=21, counterAdvanced=21, counterAtomic=21, threadname_2 with sleep for 1100 ms: counterSimple=20, counterAdvanced=20, counterAtomic=20, threadname_3 with sleep for 1100 ms: counterSimple=22, counterAdvanced=22, counterAtomic=22, threadname_1 with sleep for 1100 ms: counterSimple=24, counterAdvanced=24, counterAtomic=24, threadname_2 with sleep for 1100 ms: counterSimple=23, counterAdvanced=23, counterAtomic=23, threadname_3 with sleep for 1100 ms: counterSimple=25, counterAdvanced=25, counterAtomic=25, threadname_1 with sleep for 1100 ms: counterSimple=27, counterAdvanced=27, counterAtomic=27, threadname_2 with sleep for 1100 ms: counterSimple=26, counterAdvanced=26, counterAtomic=26, threadname_2 with sleep for 1100 ms: counterSimple=29, counterAdvanced=28, counterAtomic=28, threadname_1 with sleep for 1100 ms: counterSimple=29, counterAdvanced=29, counterAtomic=29, threadname_3 with sleep for 1100 ms: counterSimple=30, counterAdvanced=30, counterAtomic=30, threadname_2 with sleep for 1100 ms: counterSimple=31, counterAdvanced=31, counterAtomic=31, threadname_3 with sleep for 1100 ms: counterSimple=32, counterAdvanced=32, counterAtomic=32, threadname_1 with sleep for 1100 ms: counterSimple=33, counterAdvanced=33, counterAtomic=33, threadname_2 with sleep for 1100 ms: counterSimple=34, counterAdvanced=34, counterAtomic=34, threadname_1 with sleep for 1100 ms: counterSimple=36, counterAdvanced=36, counterAtomic=36, threadname_3 with sleep for 1100 ms: counterSimple=35, counterAdvanced=35, counterAtomic=35, threadname_2 with sleep for 1100 ms: counterSimple=37, counterAdvanced=37, counterAtomic=37, threadname_1 with sleep for 1100 ms: counterSimple=38, counterAdvanced=38, counterAtomic=38, threadname_3 with sleep for 1100 ms: counterSimple=39, counterAdvanced=39, counterAtomic=39, threadname_2 with sleep for 1100 ms: counterSimple=40, counterAdvanced=40, counterAtomic=40, threadname_3 with sleep for 1100 ms: counterSimple=42, counterAdvanced=42, counterAtomic=42, threadname_1 with sleep for 1100 ms: counterSimple=41, counterAdvanced=41, counterAtomic=41, threadname_2 with sleep for 1100 ms: counterSimple=43, counterAdvanced=43, counterAtomic=43, threadname_1 with sleep for 1100 ms: counterSimple=44, counterAdvanced=45, counterAtomic=45, threadname_3 with sleep for 1100 ms: counterSimple=43, counterAdvanced=44, counterAtomic=44, threadname_3 with sleep for 1100 ms: counterSimple=45, counterAdvanced=46, counterAtomic=46, threadname_1 with sleep for 1100 ms: counterSimple=47, counterAdvanced=48, counterAtomic=48, threadname_2 with sleep for 1100 ms: counterSimple=46, counterAdvanced=47, counterAtomic=47, threadname_2 with sleep for 1100 ms: counterSimple=48, counterAdvanced=49, counterAtomic=49, threadname_3 with sleep for 1100 ms: counterSimple=49, counterAdvanced=50, counterAtomic=50, threadname_1 with sleep for 1100 ms: counterSimple=50, counterAdvanced=51, counterAtomic=51, threadname_2 with sleep for 1100 ms: counterSimple=51, counterAdvanced=52, counterAtomic=52, threadname_1 with sleep for 1100 ms: counterSimple=52, counterAdvanced=53, counterAtomic=53, threadname_3 with sleep for 1100 ms: counterSimple=53, counterAdvanced=54, counterAtomic=54, threadname_2 with sleep for 1100 ms: counterSimple=54, counterAdvanced=55, counterAtomic=55, threadname_1 with sleep for 1100 ms: counterSimple=56, counterAdvanced=57, counterAtomic=57, threadname_3 with sleep for 1100 ms: counterSimple=55, counterAdvanced=56, counterAtomic=56, threadname_2 with sleep for 1100 ms: counterSimple=57, counterAdvanced=58, counterAtomic=58, threadname_1 with sleep for 1100 ms: counterSimple=59, counterAdvanced=60, counterAtomic=60, threadname_3 with sleep for 1100 ms: counterSimple=58, counterAdvanced=59, counterAtomic=59, threadname_1 with sleep for 1100 ms: counterSimple=60, counterAdvanced=61, counterAtomic=61, threadname_3 with sleep for 1100 ms: counterSimple=62, counterAdvanced=63, counterAtomic=63, threadname_2 with sleep for 1100 ms: counterSimple=61, counterAdvanced=62, counterAtomic=62, threadname_2 with sleep for 1100 ms: counterSimple=63, counterAdvanced=64, counterAtomic=64, threadname_1 with sleep for 1100 ms: counterSimple=65, counterAdvanced=66, counterAtomic=66, threadname_3 with sleep for 1100 ms: counterSimple=64, counterAdvanced=65, counterAtomic=65, threadname_2 with sleep for 1100 ms: counterSimple=66, counterAdvanced=67, counterAtomic=67, threadname_3 with sleep for 1100 ms: counterSimple=67, counterAdvanced=68, counterAtomic=68, threadname_1 with sleep for 1100 ms: counterSimple=68, counterAdvanced=69, counterAtomic=69, threadname_2 with sleep for 1100 ms: counterSimple=69, counterAdvanced=70, counterAtomic=70, threadname_3 with sleep for 1100 ms: counterSimple=70, counterAdvanced=71, counterAtomic=71, threadname_1 with sleep for 1100 ms: counterSimple=71, counterAdvanced=72, counterAtomic=72, threadname_3 with sleep for 1100 ms: counterSimple=72, counterAdvanced=73, counterAtomic=73, threadname_1 with sleep for 1100 ms: counterSimple=74, counterAdvanced=75, counterAtomic=75, threadname_2 with sleep for 1100 ms: counterSimple=73, counterAdvanced=74, counterAtomic=74, threadname_3 with sleep for 1100 ms: counterSimple=75, counterAdvanced=76, counterAtomic=76, threadname_1 with sleep for 1100 ms: counterSimple=77, counterAdvanced=78, counterAtomic=78, threadname_2 with sleep for 1100 ms: counterSimple=76, counterAdvanced=77, counterAtomic=77, threadname_2 with sleep for 1100 ms: counterSimple=78, counterAdvanced=79, counterAtomic=79, threadname_3 with sleep for 1100 ms: counterSimple=79, counterAdvanced=81, counterAtomic=81, threadname_1 with sleep for 1100 ms: counterSimple=78, counterAdvanced=80, counterAtomic=80, threadname_3 with sleep for 1100 ms: counterSimple=80, counterAdvanced=82, counterAtomic=82, threadname_2 with sleep for 1100 ms: counterSimple=81, counterAdvanced=83, counterAtomic=83, threadname_1 with sleep for 1100 ms: counterSimple=82, counterAdvanced=84, counterAtomic=84, threadname_2 with sleep for 1100 ms: counterSimple=83, counterAdvanced=85, counterAtomic=85, threadname_1 with sleep for 1100 ms: counterSimple=85, counterAdvanced=87, counterAtomic=87, threadname_3 with sleep for 1100 ms: counterSimple=84, counterAdvanced=86, counterAtomic=86, threadname_2 with sleep for 1100 ms: counterSimple=86, counterAdvanced=88, counterAtomic=88, threadname_1 with sleep for 1100 ms: counterSimple=87, counterAdvanced=89, counterAtomic=89, threadname_3 with sleep for 1100 ms: counterSimple=88, counterAdvanced=90, counterAtomic=90, threadname_3 with sleep for 1100 ms: counterSimple=89, counterAdvanced=91, counterAtomic=91, threadname_1 with sleep for 1100 ms: counterSimple=91, counterAdvanced=93, counterAtomic=93, threadname_2 with sleep for 1100 ms: counterSimple=90, counterAdvanced=92, counterAtomic=92, threadname_2 with sleep for 1100 ms: counterSimple=92, counterAdvanced=94, counterAtomic=94, threadname_1 with sleep for 1100 ms: counterSimple=94, counterAdvanced=96, counterAtomic=96, threadname_3 with sleep for 1100 ms: counterSimple=93, counterAdvanced=95, counterAtomic=95, threadname_3 with sleep for 1100 ms: counterSimple=95, counterAdvanced=97, counterAtomic=97, threadname_1 with sleep for 1100 ms: counterSimple=97, counterAdvanced=99, counterAtomic=99, threadname_2 with sleep for 1100 ms: counterSimple=96, counterAdvanced=98, counterAtomic=98, threadname_2 done sleeping threadname_1 done sleeping threadname_3 done sleeping
Conclusion
In this post, we could see an use case of the AtomicInteger class which is to able to share a counter without synchronization or lock among several threads.
Note: There is also the AtomicLong class 😉
Best regards,