ВАЖНОЕ ИЗМЕНЕНИЕ Я знаю, что "происходит до" в потоке, где выполняются два назначения, мой вопрос: возможно ли, что другой поток будет читать "b", не равный нулю, a "по-прежнему является нулевым. Поэтому я знаю, что если вы вызываете doIt() из того же потока, что и тот, где вы ранее называли setBothNonNull (...), тогда он не может вызывать исключение NullPointerException. Но что, если вы вызываете doIt() из другого потока, чем тот, который вызывает setBothNonNull (...)?
Обратите внимание, что этот вопрос касается только ключевого слова volatile
и volatile
гарантирует: не о ключе synchronized
(так что, пожалуйста, не отвечайте "вы должны использовать синхронизацию" потому что у меня нет никаких проблем: я просто хочу понять гарантии volatile
(или отсутствие гарантий) на выполнение вне порядка).
Скажем, у нас есть объект, содержащий две ссылки volatile
String, которые инициализируются нулевым конструктором и что у нас есть только один способ изменить две строки: путем вызова setBoth (...) и что мы можем установить только их ссылки впоследствии на ненулевую ссылку (только конструктору разрешено устанавливать их в null).
Например (это просто пример, пока нет вопроса):
public class SO {
private volatile String a;
private volatile String b;
public SO() {
a = null;
b = null;
}
public void setBothNonNull( @NotNull final String one, @NotNull final String two ) {
a = one;
b = two;
}
public String getA() {
return a;
}
public String getB() {
return b;
}
}
В setBothNoNull (...) строка, назначающая ненулевой параметр "a" , появляется перед тем, как строка назначит ненулевой параметр "b".
Тогда, если я это сделаю (опять же, нет вопроса, вопрос будет следующий):
doIt() {
if ( so.getB() != null ) {
System.out.println( so.getA().length );
}
}
Правильно ли я понимаю, что из-за нестандартного исполнения я могу получить исключение NullPointerException?
Другими словами: нет гарантии, что, поскольку я прочитал ненулевой "b", я прочитаю ненулевой "a" ?
Потому что из-за неуправляемого (многопроцессорного) процессора и способа volatile
работает "b", может быть назначено до "a" ?
volatile
гарантирует, что чтение после записи всегда должно видеть последнее записанное значение, но здесь есть неправильная "проблема"? (еще раз "проблема" предназначена для того, чтобы попытаться понять семантику ключевого слова volatile
и модели памяти Java, а не для решения проблемы).