Является ли оператор предварительного увеличения потокобезопасным?

Я делаю программу на Java, которая гонит несколько машин друг против друга. Каждая машина - это отдельная тема.

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

Итак, мой вопрос: является ли этот метод потокобезопасным?

 public static String completeRace()
 {
      Date accessDate = new Date();
      System.out.println("Cars Complete: " + carsComplete + " Accessed at " + accessDate.toString());
      switch(++carsComplete)
      {
           case 1: return "1st";
           case 2: return "2nd";
           case 3: return "3rd";
           default: return carsComplete + "th";    
      }
 }

5 ответов

Решение

Нет, вы должны использовать что-то вроде java.util.concurrent.atomic.AtomicInteger, Посмотрите на его getAndIncrement() метод.

++ оператор не атомарный. Посмотрите здесь http://madbean.com/2003/mb2003-44/. Для атомарных операций вы можете использовать AtomicInteger

AtomicInteger atomicInteger = new java.util.concurrent.atomic.AtomicInteger(0)

и каждый раз, когда вы хотите увеличить, вы можете позвонить atomicInteger.incrementAndGet() метод, который возвращает примитив int. 0 - начальное значение по умолчанию для атомарного целого числа.

Предварительное увеличение на int не является потокобезопасным, используйте AtomicInteger который без блокировки:

AtomicInteger carsComplete = new AtomicInteger();

//...

switch(carsComplete.incrementAndGet())

Кстати, приведенный ниже код не является потокобезопасным. Можешь сказать почему?

carsComplete.incrementAndGet();
switch(carsComplete.get())

То же, что в C++ оператор ++ не атомно.

Это на самом деле более 1 инструкции, выполняемой под капотом (не обманывайте себя, увидев просто ++i; это load/add/store) и поскольку без синхронизации задействовано более 1 инструкции, вы можете иметь различные чередования с неверными результатами.

Если вам нужно включить carsComplete потокобезопасным способом вы можете использовать конструкцию Java AtomicInteger или вы можете синхронизировать весь метод

Вопрос в том, "безопасен ли поток операций предварительного приращения?"

Ответ: нет, почему? из-за количества задействованных инструкций. Атомарный означает одну операцию, здесь необходимо выполнить операции загрузки / добавления / сохранения. Так что не атомарная операция.

  Same for post increment.
Другие вопросы по тегам