Рассмотрим следующую Java-программу:
static volatile int shared;
public static void main(final String[] args) {
final Runnable r = () -> {
shared = 1;
};
new Thread(r).start();
new Thread(r).start();
}
Поскольку shared
помечено volatile
, я хочу сказать, что эта программа свободна от гонок данных. Однако как это должно быть мотивировано на основе JLS (скажем, версия 11)?
В главе 17 нам говорят:
Когда программа содержит два конфликтующих доступа (§17.4.1), которые не упорядочены отношением «происходит до», говорят, что она содержит гонку данных.
Я принимаю это за определение гонок данных, предоставляемых JLS. Тогда у нас есть раздел 17.4.1, говорящий нам:
Два доступа к одной и той же переменной (чтение или запись в нее) называются конфликтующими, если хотя бы один из них является записью.
Хорошо, у нас здесь конфликты доступа, поскольку у нас есть две записи в shared
. Теперь между этими двумя записями должны быть отношения «до того, как это произойдет», иначе у нас гонка. Однако мне так и не удалось выяснить, почему мы имеем такое отношение. Глава 17 говорит мне, что:
Если действие x синхронизируется со следующим действием y, то у нас также есть hb (x, y).
И та же глава говорит мне:
Запись в энергозависимую переменную v (§8.3.1.4) синхронизирует все последующие чтения v любым потоком (где «последующий» определяется в соответствии с порядком синхронизации).
Но мне не удалось обнаружить, что что-то случилось, прежде чем связать записи с переменными. Почему это так?