Я, наконец, нашел хороший ответ на этот вопрос.
TL: ДР: -
Конфликтующие операции -
- Вовлечение нескольких потоков
- доступ к той же ячейки памяти
- По крайней мере один из них представляет собой операцию записи. KG
Данные гонки - неупомянутые конфликтующие операции.
LONG VERSION -
Я объясняю на примере, как конфликтующие операции происходят и как определить, если они являются данные гонки бесплатно.
Рассмотрите Thread 1
и Thread 2
и с общей переменной done
.
AtomicBoolean done = new AtomicBoolean(false);
int x = 0;
Thread 1
x = f();
done.set(true);
Thread 2
while(!done.get())
{
/* a block */
}
y = g(x);
здесь done.set() - done.get()
и x=f() - y=g(x)
находятся в конфликте. Однако модель памяти программирования определяет 2 отношения: - synchronizes-with
и happens-before
. Поскольку done
является атомарным, его пара операций синхронизируется друг с другом. Кроме того, из-за этого мы можем выбрать, какая операция happens before
другая в этой паре.
Теперь, потому что x = f()
происходит перед done.set(true)
в теме 1 и done.get()
происходит перед y = g(x)
в теме 2, мы можем сказать, x = f()
происходит до y = g(x)
потому, что происходит перед транзитивным отношением.
Таким образом, приведенный выше пример заказан и, следовательно, беспроволочный.