В моем приложении мне нужно лениво устанавливать переменную, поскольку у меня нет доступа к необходимым методам во время инициализации класса, но мне также нужно, чтобы это значение было доступно в нескольких потоках. Я знаю, что могу использовать двойную проверку блокировки для решить эту проблему, но это кажется излишним. Метод, который мне нужно вызвать для получения значения, является идемпотентным, и возвращаемое значение никогда не изменится. Я хотел бы лениво инициализировать ссылку, как если бы я находился в однопоточной среде. Похоже, это должно работать, поскольку чтение и запись в ссылки являются атомарными. [1] [2]
Вот пример кода того, что я делаю.
// views should only be accessed in getViews() since it is
// lazily initialized. Call getViews() to get the value of views.
private List<String> views;
/* ... */
private List<String> getViews(ServletContext servletContext) {
List<String> views = this.views;
if (views == null) {
// Servlet Context context and init parameters cannot change after
// ServletContext initialization:
// https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html#setInitParameter(java.lang.String,%20java.lang.String)
String viewsListString = servletContext.getInitParameter(
"my.views.list.VIEWS_LIST");
views = ListUtil.toUnmodifiableList(viewsListString);
this.views = views;
}
return views;
}
Этот вопрос о 32-битных примитивах аналогичен, но я хочу подтвердить, что поведение то же самое для ссылок на такие объекты, как String
s и List
s.
По-видимому, это должно работать нормально, поскольку каждый поток либо увидит null
и повторно вычислит значение (не проблема, поскольку значение никогда не изменится), либо увидит уже вычисленное значение. Я здесь упускаю какие-то подводные камни? Является ли этот код потокобезопасным?