Я хотел бы связать вышеуказанный оператор с некоторым примером потока кода.
Чтобы понять это, возьмем ниже класс, который имеет два поля: counter
и isActive
.
class StateHolder {
private int counter = 100;
private boolean isActive = false;
public synchronized void resetCounter() {
counter = 0;
isActive = true;
}
public synchronized void printStateWithLock() {
System.out.println("Counter : " + counter);
System.out.println("IsActive : " + isActive);
}
public void printStateWithNoLock() {
System.out.println("Counter : " + counter);
System.out.println("IsActive : " + isActive);
}
}
И предположим, что есть три нити T1, T2, T3 вызвать следующие методы на одном объекте StateHolder
:
T1 называет resetCounter()
и Т2 вызывает printStateWithLock()
в то же время и Т1 получает блокировку
T3 -> вызывает printStateWithNoLock()
после T1 завершения его выполнения
следует отметить, что наличие происходит, прежде, чем отношения между двумя действиями делает п ot обязательно подразумевают, что они должны выполняться в этом порядке в ходе реализации. Если переупорядочение приводит к результатам, соответствующим законному исполнению, это не является незаконным.
и непосредственная линия говорит,
В соответствии с вышеуказанным заявлением, что дает гибкость для виртуальной машины Java, OS или базового оборудования, чтобы изменить порядок утверждения в рамках метода resetCounter()
. И по мере запуска T1 он может выполнять инструкции в следующем порядке.
public synchronized void resetCounter() {
isActive = true;
counter = 0;
}
Это рядный с утверждением не обязательно означает, что они должны иметь место в том порядке, в реализации.
Теперь, рассматривая его с точки зрения T2, это переупорядочение не оказывает никакого отрицательного воздействия, поскольку оба T1 и T2 синхронизируются на одном и том же объекте, и T2 гарантированно увидит изменения изменений в обоих полях, независимо от того, о том, произошло ли переупорядочение или нет, как это происходит - до отношений. Так выход всегда будет:
Counter : 0
IsActive : true
Это согласно заявлению, Если переназначения дает результаты в соответствии с юридическим оформлением, это не является незаконным
Но смотреть на него с точки зрения T3, с это переупорядочивает возможность того, что T3 увидит обновленное значение isActive
как «true but still see the
счетчик value as
100`, хотя T1 завершил выполнение.
Counter : 100
IsActive : true
Следующая точка в указанной выше ссылке далее уточняет заявление и говорит, что:
Более конкретно, если два действия разделяют происходит-до отношений, они не обязательно должны появляться иметь произошли в этом порядке с любым кодом, с которым они не разделяют связь между событиями. Записи в одном потоке, которые находятся в гонке данных с чтением в другом потоке, могут, например, появляться не по порядку для этих чтений.
В этом примере T3 столкнулся с этой проблемой, так как ее не происходит - до отношения с T1 или T2. Это inline с Не обязательно должно появляться в том порядке, в каком порядке, с каким кодом, с которым они не имеют отношения «произойти раньше».
ПРИМЕЧАНИЕ: Для упрощения случая у нас есть одна нить T1, изменяющая состояние, а T2 и T3 считывают состояние. Можно иметь
обновления T1 counter to 0
, позже
T2 изменяет IsActive в true
и видит counter is 0
, после того, как когда-то
T3, который печатает состояние все еще мог видеть only isActive as true but counter is 100
, хотя оба T1 и T2 завершили выполнение.
Что касается последнего вопроса:
мы имеем Hb (ш, г), но это не значит, что с будет содержать значение 3 после присвоения. Как обеспечить, чтобы c был назначен 3?
public volatile int v;
public int c;
Thread A
v = 3; //w
Thread B
c = v; //r
Поскольку v
является летучим, согласно Happens-before Order
Запись в летучем поле (§8.3.1.4) происходит-перед каждым последующим чтения этого поля.
Так что можно с уверенностью предположить, что, когда Thread B пытается прочитать переменную v
всегда будет читать обновленное значение и c
будут назначены 3 в приведенном выше коде.
@Eugene, спасибо. Я обновил свой ответ, чтобы отразить ваш комментарий. –