Раздел 3.2.1 Goetz "Java Concurrency in Practice" содержит следующее правило:
Не разрешайте ссылку
thisуйти во время построения
Я понимаю, что в общем случае разрешение this на выход может привести к тому, что другие потоки будут видеть неполностью сконструированные версии вашего объекта и нарушают гарантию безопасности инициализации полей final (как обсуждалось, например, здесь)
Но можно ли безопасно протекать this? В частности, если вы установили связь happen-before до утечки?
Например, официальный исполнитель Javadoc говорит
Действия в потоке перед отправкой объекта
RunnableвExecutorпроизойдет - до его запуска, возможно, в другом потоке
Мое наивное понимание чтения модели памяти Java заключается в том, что что-то вроде следующего должно быть безопасным, даже если оно протекает this до конца конструктора:
public final class Foo {
private final String str1;
private String str2;
public Foo(Executor ex) {
str1 = "I'm final";
str2 = "I'm not";
ex.execute(new Runnable() {
// Oops: Leakage!
public void run() { System.out.println(str1 + str2);}
});
}
}
То есть, несмотря на то, что мы пропустили this потенциально злонамеренный Executor, назначения перед str1 и str2 произойдут - до утечки, поэтому объект полностью (целиком и полностью) построенный, хотя он не был "полностью инициализирован" на JLS 17.5.
Обратите внимание, что я также требую, чтобы класс был final, поскольку любые поля подкласса были инициализированы после утечки.
Я что-то упустил? Действительно ли это гарантировано, что он хорошо себя ведет? Он выглядит как законный пример "Piggybacking on synchronization" (16.1.4). В целом я был бы очень признателен за любые указания на дополнительные ресурсы, в которых эти проблемы будут рассмотрены.
EDIT. Я знаю, что, как заметил @jtahlborn, я могу избежать проблемы с помощью публичного статического factory. Я ищу ответ на вопрос непосредственно, чтобы укрепить мое понимание модели памяти Java.
EDIT # 2: Этот ответ ссылается на то, к чему я пытаюсь добраться. То есть, следуя правилу из приведенного там JLS, достаточно для обеспечения видимости всех полей final. Но нужно ли это, или мы можем использовать другие механизмы, чтобы обеспечить наши гарантии на видимость?