последние поля и потокобезопасность - PullRequest
8 голосов
/ 22 августа 2011

Должно ли это быть все поля, включая суперполя, целенаправленно неизменяемого Java-класса 'final', чтобы быть потокобезопасным, или этого достаточно, чтобы не иметь методов-модификаторов?

Предположим, у меня есть POJO с неконечными полями, где все поля являются типом некоторого неизменяемого класса. Этот POJO имеет геттеры-сеттеры и конструктор, который устанавливает некоторое начальное значение. Если я расширю этот POJO с помощью методов-модификаторов, выбив их из строя, сделав его неизменным, будет ли класс расширения поточно-ориентированным?

Ответы [ 2 ]

14 голосов
/ 22 августа 2011

Чтобы использовать эффективно неизменяемый объект без полей final потокобезопасным способом, необходимо использовать один из безопасных идиом публикации, когда объект становится доступным для других потоков после инициализации, в противном случае эти потоки могут видеть объект частичноинициализированное состояние (из Java-параллелизма на практике ):

  • Инициализация ссылки на объект из статического инициализатора;
  • Сохранение ссылки на него вvolatile field или AtomicReference;
  • Сохранение ссылки на него в конечном поле правильно построенного объекта;или
  • Сохранение ссылки на него в поле, которое должным образом защищено замком.

Объявление полей вашего неизменяемого объекта как final снимает это ограничение (т.е.это гарантирует, что если другие потоки увидят ссылку на объект, они также увидят его final поля в полностью инициализированном состоянии).Однако в общем случае это не гарантирует, что другие потоки смогут увидеть ссылку на объект, как только он был опубликован, поэтому вам, возможно, все же придется использовать безопасную публикацию, чтобы обеспечить его.

Обратите внимание, что если вашобъект реализует интерфейс, вы можете использовать подход, используемый Collections.unmodifiableList(), и т. д .:

class ImmutableFooWrapper implements IFoo {
    private final IFoo delegate; // final provides safe publication automatically

    public ImmutableFooWrapper(IFoo delegate) {
        this.delegate = delegate;
    }
    ...
}

public IFoo immutableFoo(IFoo foo) {
    return new ImmutableFooWrapper(foo);
}
0 голосов
/ 22 августа 2011

Да, он будет неизменным и, следовательно, потокобезопасным, но только до тех пор, пока поля являются частными.

...