Странное поведение кодового кода

В настоящее время я изучаю Java concurrency. И я очень удивлен тем, как ведет себя код.

import java.util.concurrent.*;

public class Exercise {
    static int counter = 0;

    static synchronized int getAndIncrement() {
        return counter++;
    }

    static class Improper implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 300; i++) {
                getAndIncrement();
            }
        }
    }


    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 300; i++) {
            executorService.submit(new Improper());
        }
        executorService.shutdown();
        System.out.println(counter);
    }
}

Должно ли оно выводить 90000 все время? Вместо этого результат различается все время.

Ответ 1

  • executorService.shutdown() не дождался завершения работы службы. Вам нужно позвонить awaitTermination.

  • вы получаете доступ к counter из основного метода без блокировки. Я думаю, что вы едва ли избежите гонки данных, если вы ожидаете, что служба-исполнитель отключится, но предупреждайте, что в общем случае вы должны синхронизировать все обращения к общей переменной, а не только записи, чтобы иметь какие-либо гарантии видимости от Модель памяти Java.

Ответ 2

Вам нужно убедиться, что все задачи успели закончить. Используйте awaitTermination

public static void main(String[] args) throws InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 300; i++) {
        executorService.submit(new Improper());
    }
    executorService.shutdown();
    executorService.awaitTermination(2, TimeUnit.SECONDS);
    System.out.println(counter);
}

Ответ 3

Вы не ждете завершения всех ваших подчиненных задач, см. javadoc для ExecutorService.html#shutdown. Таким образом, получение произвольного результата каждый раз является ожидаемым поведением.