Потоково-безопасно ли лениво инициализировать ссылки, если записанное значение всегда одинаково? - PullRequest
0 голосов
/ 23 мая 2018

В моем приложении мне нужно установить переменную лениво, поскольку у меня нет доступа к необходимым методам во время инициализации класса, но мне также нужно, чтобы это значение было доступно для нескольких потоков.Я знаю, что мог бы использовать дважды проверенную блокировку , чтобы решить эту проблему, но это кажется излишним. Метод, который мне нужно вызвать для получения значения, идемпотентен, и возвращаемое значение никогда не изменится. Я бы хотел лениво инициализировать ссылку, как если бы я находился в однопоточном окружении.Кажется, что это должно работать, поскольку чтение и запись в ссылки являются атомарными. [ 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 и пересчитает значение (не проблема, так как значение никогда не изменится), либо увидит уже вычисленное значение.Я пропускаю какие-либо подводные камни здесь?Этот код является потокобезопасным?

1 Ответ

0 голосов
/ 23 мая 2018

Этот вопрос о 32-битных примитивах похож, но я хочу подтвердить, что поведение относится к ссылкам на объекты, такие как строки и списки.

Да, потому что написание ссылоквсегда атомарен для JLS :

Запись и чтение ссылок всегда атомарны, независимо от того, реализованы они как 32-битные или 64-битные значения.

Питер Лоури отмечает , что это действительно с Java 5 и выше.

Но обратите внимание Наблюдение Ивана :

Без синхронизации (блок синхронизации или энергозависимый) у вас может получиться, что каждый поток имеет свой собственный экземпляр списка (каждый поток может увидеть это views == null и инициализировать переменную и использовать свою собственную копию списка)

... и вопрос Эриксона :

В соответствии с этой реализацией каждый поток может иметь свой экземпляр views.Это нормально?

...