Является ли оператор предварительного увеличения потокобезопасным?
Я делаю программу на 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.