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

Я делаю программу на 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 ]

26 голосов
/ 04 октября 2011

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

9 голосов
/ 04 октября 2011

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

AtomicInteger carsComplete = new AtomicInteger();

//...

switch(carsComplete.incrementAndGet())

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

carsComplete.incrementAndGet();
switch(carsComplete.get())
7 голосов
/ 04 октября 2011

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

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

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

6 голосов
/ 04 октября 2011

То же, что и в C ++, оператор ++ не является атомарным.

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

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

2 голосов
/ 10 июня 2015

Вопрос «потокобезопасен ли оператор предварительного приращения?»

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

  Same for post increment.
...