ExecutorService с AtomicInteger и Synchronized дают разные результаты - PullRequest
1 голос
/ 02 февраля 2020

Ниже приведен код - 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());
    }
}

Выход вышеуказанного кода:

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

Тот же код заменяет AtomicInteger на int и синхронизированный блок

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());
    }
}

Вывод синхронизированного кода блока

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

Вопрос?

  1. Почему существует разница в выходах?
  2. Почему атомное число c увеличивается до 2 вместо 1.
  3. Как получить синхронизированный выход с помощью atomicinteger.
  4. Любое преимущество или использование совместного использования volatile и atomi c?

1 Ответ

0 голосов
/ 02 февраля 2020

AtomicInteger использует поле volatile под колпаком. Это означает, что все читатели (другие темы) используют самое актуальное значение. При использовании простого int во втором случае ваше поле не равно volatile, поэтому наблюдаемое 1 исходит из устаревшего значения.

Используя ключевое слово volatile, вы должны может достигать аналогичных результатов.

Другой способ - использовать ворота, чтобы обеспечить выполнение условия, прежде чем двигаться дальше. Это может быть достигнуто с помощью CountDownLatch, например (есть и другие способы): https://www.baeldung.com/java-countdown-latch

...