Как понимать происходит - до согласованного

В глава 17 JLS в ней вводится понятие: бывает - до согласованного.

Выполняется множество действий A - до согласованного, если для всех читает r в A, где W (r) - это действие записи, наблюдаемое r, то нет необходимости в том, чтобы либо hb (r, W (r)), или что существует запись w в такая, что wv = rv и hb (W (r), w) и hb (w, r) "

В моем понимании он равен следующим словам: ..., это так, что ни..., ни...

Итак, мои первые два вопроса:

  • Правильно ли я понимаю?
  • Что означает "w.v = r.v"?

Он также дает пример: 17.4.5-1

Thread 1 Thread 2

B = 1; A = 2; 

r2 = A; r1 = B; 

В первом порядке выполнения:

1: B = 1;

3: A = 2;

2: r2 = A;  // sees initial write of 0

4: r1 = B;  // sees initial write of 0

Сам заказ уже сказал нам, что два потока выполняются поочередно, поэтому мой третий вопрос: что означает левое число?

В моем понимании, причина как r2, так и r1 может видеть, что начальная запись 0 является как A, так и B не изменчивым полем. Итак, мой четвертый quesiton: правильно ли я понимаю?

Во втором порядке выполнения:

1: r2 = A;  // sees write of A = 2

3: r1 = B;  // sees write of B = 1

2: B = 1;

4: A = 2;

В соответствии с определением происшествия - до согласованности, нетрудно понять, что это исполнение выполняется, - до согласованного (если мое первое понимание правильное). Итак, мои пятый и шестой вопросы: существует ли такая ситуация (читает см. Записи, которые происходят позже) в реальном мире? Если да, не могли бы вы дать мне настоящий пример?

Ответ 1

Каждый поток может быть на другом ядре с собственным кешем. Это означает, что один поток может записывать в хранилище значений в регистре или его локальном кеше, и это значение некоторое время не отображается в другом потоке. (миллисекунды не редкость)

Более экстремальным примером является то, что код потока чтения оптимизирован с предположением, что, поскольку он никогда не изменяет значение, ему не нужно читать его из памяти. В этом случае оптимизированный код никогда не видит изменения, выполненные другим потоком.

В обоих случаях использование volatile гарантирует, что чтение и запись происходят в последовательном порядке, и оба потока видят одно и то же значение. Это иногда описывается как всегда чтение из основной памяти, хотя это не обязательно, потому что кеши могут напрямую разговаривать друг с другом. (Таким образом, удар производительности намного меньше, чем вы могли ожидать)

Ответ 2

Модель памяти Java определяет частичное упорядочение всех ваших действий вашей программы, которая называется before-before.
Чтобы гарантировать, что поток Y способен видеть побочные эффекты действия X (не имеет значения, если X произошел в другом потоке или нет), между X и Y определяется соотношение между событиями-before.
Если такой связи нет, JVM может переопределить операции программы.
Теперь, если переменная является общей и доступной для многих потоков и написана (по крайней мере) одним потоком, если чтения и записи не упорядочиваются, когда происходит до отношения, то у вас есть гонка данных.
В правильной программе нет гонок данных.
Пример: 2 потока A и B синхронизированы при блокировке X.
Thread A получает блокировку (теперь Thread B заблокирован) и выполняет операции записи, а затем освобождает блокировку X. Теперь Thread B получает блокировку X, и поскольку все действия Thread A выполнялись до освобождения блокировки X, они упорядочиваются перед действиями Thread B, которые получили блокировку X после потока A (а также видно на Thread B).
Обратите внимание, что это происходит при выполнении действий, синхронизированных с одной и той же блокировкой. Между отношениями, синхронизированными на разных шлюзах, не происходит событий

Ответ 3

По существу это правильно. Главное, чтобы вытащить из этого: если вы не используете какую-то форму синхронизации, нет никакой гарантии, что чтение, которое приходит после записи в вашем программном заказе, видит эффект этой записи, поскольку утверждения могли быть пересмотрены.

существует ли такая ситуация (читает см. записи, которые происходят позже) в реальном мире? Если да, не могли бы вы дать мне настоящий пример?

С точки зрения настенных часов, очевидно, чтение не может видеть эффект записи, которая еще не была выполнена.

С точки зрения программы, потому что операторы могут быть переупорядочены, если нет надлежащей синхронизации (происходит до отношения), чтение, которое приходит до записи в вашей программе, может видеть эффект этой записи во время выполнения, потому что она был выполнен после записи JVM.

Ответ 4

Это означает, что если механизм синхронизации отсутствует, вы можете увидеть счетчик воздействий интуитивно.

volatile int A = 0;
volatile int B = 0;
1: B = 1;
2: r2 = A; // r2 guarantees the value 1
3: A = 2;         
4: r1 = B; // r1 guarantees the value 2

Это потому, что гарантии изменчивых переменных происходят перед отношением. Если A и B не являются изменчивыми, система может изменить порядок оценки переменных, и это может стать противоречивым.

Ответ 5

Давайте начнем с некоторых из наиболее важных аспектов параллелизма:

Атомарность

Атомарность - это все о неделимых операциях, то есть они либо произойдут полностью, либо не произойдут вообще. Лучший пример атомарной операции в Java - это присвоение значения переменной.

Видимость

Видимость касается одного аспекта: будут ли изменения (или эффекты), сделанные одним потоком в общей переменной, видны другим потокам или нет?

Заказ

Упорядочение - все о том, может ли порядок инструкций в исходном коде быть изменен компилятором во имя оптимизации или нет. Существует вероятность того, что действия в одном потоке могут происходить не по порядку относительно другого.

случается, перед тем

Официальный документ

Два действия могут быть упорядочены отношениями "происходит до". Если одно действие происходит раньше другого, то первое видимо для, а заказывает перед вторым.

enter image description here

летучий

Запись в энергозависимое поле происходит перед каждым последующим чтением того же поля.

Когда мы записываем в переменную volatile[About] it creates a happens-before relationship with each subsequent read of that same variable. So any memory writes that have been done until that volatile variable write, will subsequently be visible to any statements that follow the read of that volatile variable.

это создает отношение happens-before при каждом последующем чтении этой же переменной. Таким образом, любые записи в память, которые были выполнены до записи этой изменчивой переменной, впоследствии будут видны любым операторам, которые следуют за чтением этой изменчивой переменной.
// Definition: Some variables
int a = 1;
int b = 2;
volatile boolean myVolatile = false;

// Thread 1. Program order
a = 5;
b = 6;
hasValue = true;

//Thread 2. Program order
System.out.println(myVolatile);
System.out.println(a);  // will print 5
System.out.println(b);  // will print 6

Предположим, что два приведенных выше фрагмента выполняются двумя разными потоками - Thread 1 и Thread 2. Когда Thread 1 изменит hasValue, это также приведет к тому, что предыдущие записи будут сброшены в основную память. В результате Thread 2 увидит все записи, сделанные Thread 1

JVM славится своей программной оптимизацией. Иногда это изменяет порядок программных операторов, чтобы повысить производительность без изменения вывода программы. Например, он может изменить следующую последовательность операторов:

a = 5;
b = 6;

В это:

b = 6;
a = 5;

Однако, когда операторы включают в себя доступ к переменной volatile, тогда он никогда не будет перемещать оператор, встречающийся перед изменчивой записью после него.

//This will never happen!
int a = 1;
volatile boolean myVolatile = false;
int b = 2;

Обратите внимание, что JVM по-прежнему разрешается переупорядочивать записи до того, как они будут записаны до тех пор, пока все они не появятся до энергозависимой записи.

int b = 2;
int a = 1;
volatile boolean myVolatile = false;

Аналогично, JVM также не изменит порядок оператора, который появляется после чтения изменяемой переменной, чтобы появиться перед доступом.

Узнайте больше здесь, здесь, здесь, здесь