Состояние гонки при использовании Atomic Integer - PullRequest
0 голосов
/ 16 июня 2019

Я изучаю пакет java.util.concurrent.atomic и пробую свои силы на Atomic Integer.Насколько я понимаю, пакет Atomic помогает писать код без блокировки, а не синхронизированный блок.Поэтому, чтобы проверить мое понимание, я написал следующий код:

public class Test{

   private final AtomicInteger ai; 

   public void increment() {
        int oldVal = ai.get();

        while(!ai.compareAndSet(oldVal, oldVal+1)) {
            oldVal = ai.get();
        }
    }

    public int incrementModified() {
        return ai.incrementAndGet();
    }

    public int get() {
        return ai.get();
    }

public static void main(String[] args) {
        Test pc = new Test(5);

        Runnable r1 = () -> {
            pc.increment();
        };

        Runnable r2 = () -> {
            pc.increment();
        };

        Runnable r3 = () -> {
            pc.increment();
        };

        Thread t1 = new Thread(r1);

        Thread t2 = new Thread(r2);

        Thread t3 = new Thread(r3);

        t1.start();
        t2.start();
        t3.start();

        System.out.println(pc.get());

    }

Когда я выполняю приведенный выше код, я ожидаю, что результат будет 8 , но я получаю вывод как 7 /8 .Затем я даже использовал встроенный метод incrementAndGet() и по-прежнему получал один и тот же вывод после запуска программы несколько раз.

Насколько я понимаю, поскольку атомарный можно использовать в качестве альтернативы синхронизированному блоку, и он делаетинкрементные операции приращения с использованием CAS (сравнить и установить инструкцию), я всегда должен получать выходные данные как 8.

Но так как я получаю различные выходные данные, я предполагаю, что существует гонка, и, таким образом, o / p изменяется между 7/8.

Может ли кто-нибудь указать на ошибки, которые я совершаю в приведенном выше коде, или исправить мои представления об атомарных классах в Java?

РЕДАКТИРОВАТЬ:

Как отмечено в комментариях, я не использовал join() и, таким образом, получал неверный результат, поскольку основной поток запрашивал значение, в то время как какой-то поток все еще находился в середине операции.Я добавил его, и после нескольких тестирований я могу увидеть ожидаемый результат.

1 Ответ

2 голосов
/ 16 июня 2019

Строка, которая печатает значение, выполняется одновременно с тремя другими потоками. Если вы хотите убедиться, что он выполняется после запуска 3-х потоков, вам нужно присоединиться () к этим потокам.

...