1

Following is the code - AtomicInteger

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class ExecutorExample1 {
    public static void main(String[] args) {
        ExecutorService executorService= Executors.newFixedThreadPool(2);
        executorService.execute(new MyTask());
        executorService.execute(new MyTask());
        executorService.execute(new MyTask());
        executorService.shutdown();
    }
}

class MyTask implements Runnable{
    private static AtomicInteger count = new AtomicInteger(0);
    @Override
    public void run() {
        try {
            count.addAndGet(1);
            task();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void task()throws InterruptedException{
        System.out.println(count + " Enterd Run of: " + Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(count + " Executing: " + Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(count + " Completed Executing: " + Thread.currentThread().getName());
    }
}

Ouput of above code:

2 Enterd Run of: pool-1-thread-1
2 Enterd Run of: pool-1-thread-2
2 Executing: pool-1-thread-2
2 Executing: pool-1-thread-1
2 Completed Executing: pool-1-thread-1
2 Completed Executing: pool-1-thread-2
3 Enterd Run of: pool-1-thread-1
3 Executing: pool-1-thread-1
3 Completed Executing: pool-1-thread-1

Same code replacing AtomicInteger with int and synchronized block

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class ExecutorExample1 {
    public static void main(String[] args) {
        ExecutorService executorService= Executors.newFixedThreadPool(2);
        executorService.execute(new MyTask());
        executorService.execute(new MyTask());
        executorService.execute(new MyTask());
        executorService.shutdown();
    }
}

class MyTask implements Runnable{
    //private static AtomicInteger count = new AtomicInteger(0);
    private static int count = 0;
    @Override
    public void run() {
        try {
            //count.addAndGet(1);
            synchronized (MyTask.class){
                count+=1;
            }
            task();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void task()throws InterruptedException{
        System.out.println(count + " Enterd Run of: " + Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(count + " Executing: " + Thread.currentThread().getName());
        Thread.sleep(5000);
        System.out.println(count + " Completed Executing: " + Thread.currentThread().getName());
    }
}

Output of Synchronized block code

2 Enterd Run of: pool-1-thread-2
1 Enterd Run of: pool-1-thread-1
2 Executing: pool-1-thread-2
2 Executing: pool-1-thread-1
2 Completed Executing: pool-1-thread-2
2 Completed Executing: pool-1-thread-1
3 Enterd Run of: pool-1-thread-2
3 Executing: pool-1-thread-2
3 Completed Executing: pool-1-thread-2

Question?

  1. Why is there a difference in outputs?
  2. Why the atomic integer is getting incremented to 2 instead of 1.
  3. How do I acheive the synchronised output with atomicinteger.
  4. Any benefit or use of using volatile and atomic together?

1 Answers1

0

An AtomicInteger uses a volatile field under the hood. What this does is that it makes sure that all readers (other threads) use the most up-to-date value. When using a simple int in your second case, your field is not volatile so the 1 you are seeing is coming from a stale value.

By using the volatile keyword you should be able to achieve similar results.

Another way would be to use a gate to ensure a condition is met before moving on further. This can be achieved with a CountDownLatch for example (there are other ways too): https://www.baeldung.com/java-countdown-latch

zlandorf
  • 1,100
  • 11
  • 15
  • Using atomicinteger why is the count getting incremented from 0 to 2 instead of 1? – Manan Mehta Feb 02 '20 at 11:29
  • 1
    If you run it enough times, you will find cases where it goes to 1 first. When you see 2 first, it just means that both threads executed the increment before printing anything. – zlandorf Feb 02 '20 at 12:07