Примечание
Говоря, что доступ к памяти может (или не может) быть переупорядочен я meand, что это может быть
переупорядочивается либо компилятором при испускании байтового байтового байта, либо JIT при испускании
машинный код или ЦП при исполнении из строя (в конечном итоге требуя препятствий для предотвращения этого) в отношении любого другого доступа к памяти.
Если часто читается, что доступ к переменным volatile
не может быть переупорядочен из-за отношений Happens-Before (HBR).
Я обнаружил, что HBR существует между каждыми двумя последовательными (в программном порядке) действиями данный поток, и все же они могут быть переупорядочены.
Также недействительный доступ HB только с доступом в той же переменной/поле.
Я думаю, что volatile
не перезаписывается, это
Записывается в изменчивое поле (§8.3.1.4) - перед каждым последующим чтением [любого потока] этого поля.
Если есть другие потоки, переупорядочение переменных станет видимым, как в этом простой пример
volatile int a, b;
Thread 1 Thread 2
a = 1; while (b != 2);
b = 2; print(a); //a must be 1
Таким образом, сам HBR не препятствует упорядочению, но тот факт, что volatile
расширяет эту взаимосвязь с другими потоками, присутствие других потоков является элементом, который предотвращает переупорядочение.
Если компилятор может доказать, что переупорядочение изменчивой переменной не изменит
семантика программы, она может переупорядочить его , даже если есть HBR.
Если переменная volatile недоступна другим потокам, чем ее обращения может быть переупорядочено
volatile int a, b, c;
Thread 1 Thread 2
a = 1; while (b != 2);
b = 2; print(a); //a must be 1
c = 3; //c never accessed by Thread 2
Я думаю, что c=3
вполне может быть переупорядочено до a=1
, эта цитата из спецификаций
подтвердите это
Следует отметить, что наличие взаимосвязи между случаями два действия не обязательно означают, что они должны проходить в этом порядке в реализации. Если переупорядочение дает результаты, соответствующие это не является незаконным.
Итак, я сделал эти простые java-программы
public class vtest1 {
public static volatile int DO_ACTION, CHOOSE_ACTION;
public static void main(String[] args) {
CHOOSE_ACTION = 34;
DO_ACTION = 1;
}
}
public class vtest2 {
public static volatile int DO_ACTION, CHOOSE_ACTION;
public static void main(String[] args) {
(new Thread(){
public void run() {
while (DO_ACTION != 1);
System.out.println(CHOOSE_ACTION);
}
}).start();
CHOOSE_ACTION = 34;
DO_ACTION = 1;
}
}
В обоих случаях оба поля помечены как volatile
и доступны с помощью putstatic
.
Поскольку это все данные, которые JIT имеет 1 машинный код будет идентичным,
таким образом, обращения vtest1
не будут оптимизированы 2.
Мой вопрос
Неужели волатильные обращения действительно никогда не переупорядочиваются по спецификации или они могут быть 3 но это никогда не делается на практике?
Если неустойчивые обращения никогда не могут быть переупорядочены, какие части спецификаций так говорят? и будет ли это означать, что все изменчивые обращения выполняются и рассматриваются в программном порядке процессорами?
1 Или JIT может знать, что поле никогда не будет доступно другим потоком? Если да, то как?.
2 Например, будут присутствовать барьеры памяти.
3 Например, если не задействованы никакие другие потоки.