Мне интересно, какие гарантии публикации существуют для неокончательного поля, инициализированного значением null, если таковое имеется.

Рассмотрим следующий фрагмент:

public class MyClass {

    private final CopyOnWriteArrayList<Inner> list = new CopyOnWriteArrayList<>();

    //called by thread 1
    public void init() {
        // initialise Inner instance
        list.add(new Inner());
    }

    //called by thread 2
    public void doSomething() {
        for (Inner i : list) {
            // access non-final field
            Object ref = i.ref;
            // do something
            // ...
            // ...

            // potentially set i.ref
        }
    }

    private static class Inner {
        // initialised by thread 1
        Object ref = null;
    }
}

Предполагая, что doSomething() всегда вызывается потоком 2, это безопасно? Какие гарантии даются относительно того, какой поток 2 увидит при первом обращении к нему? Есть ли вероятность, что поток 2 увидит что-то ненулевое?

Где в JMM описывается семантика этой ситуации?

2
user2248785 25 Сен 2018 в 13:53

2 ответа

Лучший ответ

JVM гарантирует, что вы не увидите неожиданных значений , поэтому ничего, кроме null это невозможно , в случае, если { {X2}} не является пустым (в этом примере, конечно). Если бы был задействован другой поток (скажем, Thread3), который изменил бы ваш список (добавил в него элементы), Thread2 мог бы увидеть эти обновления. Просто обратите внимание, что отдельные методы CopyOnWriteArrayList потокобезопасны; ваш метод doSomething не .

См. JLS для уточнения или отличного (и довольно сложного, может быть, только для меня) Алексей статья.

1
Eugene 2 Окт 2018 в 13:11

Говорить о безопасной публикации имеет смысл только тогда, когда вы инициализируете поле значимым объектом, имеющим состояние . Затем неправильная публикация может привести к наблюдению частично сконструированного объекта .

В этом случае null не передает никакого состояния . Его можно рассматривать неизменяемый объект . Неизменяемые объекты не имеют проблем с публикацией.

Какие гарантии даются относительно того, какой поток 2 увидит при первом обращении к нему?

Поток 2 увидит null при обращении к i.ref.
Обратите внимание, что список может быть пустым, потому что Поток 1, возможно, еще не добавил к нему Inner.

Есть ли вероятность, что поток 2 увидит что-то ненулевое?

Нет.

0
Andrew Tobilko 25 Сен 2018 в 11:22