Ответ 1
Это два вопроса. Начните со второго.
Назначение вновь построенных объектов для изменчивых переменных прекрасно работает. Каждый поток, который читает изменчивую переменную, будет видеть полностью построенный объект. Нет необходимости в дальнейшей синхронизации. Этот шаблон обычно рассматривается в сочетании с неизменяемыми типами.
class Tree {
private volatile Node node;
public void update() {
node = new Node(...);
}
public Node get() {
return node;
}
}
Относительно первого вопроса. Вы можете использовать изменчивые переменные для синхронизации доступа к энергонезависимой переменной. В следующем листинге показан пример. Представьте себе, что две переменные инициализируются, как показано, и что оба метода выполняются одновременно. Гарантируется, что если второй поток увидит обновление до foo
, оно также увидит обновление до bar
.
volatile int foo = 0;
int bar = 0;
void thread1() {
bar = 1;
foo = 1; // write to volatile variable
}
void thread2() {
if (foo == 1) { // read from volatile variable
int r = bar; // r == 1
}
}
Однако ваш пример отличается. Чтение и запись могут выглядеть следующим образом. В отличие от вышеприведенного примера, оба потока считываются из изменчивой переменной. Однако операции чтения с изменчивыми переменными не синхронизируются друг с другом.
void thread1() {
Node temp = root; // read from volatile variable
temp.numOfKeys = 1;
}
void thread2() {
Node temp = root; // read from volatile variable
int r = temp.numOfKeys;
}
Другими словами: если поток A записывает в изменчивую переменную x, а поток B считывает значение, записанное в x, то после операции чтения поток B будет видеть все операции записи потока A, которые произошли до записи в x, Но без операции записи с изменчивой переменной не влияет на обновления других переменных.
Это звучит сложнее, чем есть на самом деле. На самом деле, есть только одно правило, которое вы можете найти в JLS8 §17.4.5:
[..] Если все последовательные последовательные исполнения свободны от расчётов данных, [..], то все исполнения программы кажутся последовательно последовательными.
Проще говоря, гонка данных существует, если два потока могут одновременно обращаться к одной и той же переменной, по крайней мере одна операция - операция записи, а переменная является энергонезависимой. Горы данных можно устранить, объявив общие переменные волатильными. Без гонок данных нет проблем с видимостью обновлений.