Самый дешевый способ установить, что происходит раньше, с не финальным полем

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

Однако я не вижу ответа на этот вопрос: если семантика класса такова, что поле не может бытьfinalНо кто-то хочет обеспечить «публикацию» поля и идентифицированного им объекта, каков наиболее эффективный способ сделать это? В качестве примера рассмотрим

class ShareableDataHolder<T>
{
  Object data; // Always identifies either a T or a SharedDataHolder<T>
}
private class SharedDataHolder<T> extends ShareableDataHolder<T>
{
  Object data; // Always identifies either a T or a lower-numbered SharedDataHolder<T>
  final long seq; // Immutable; necessarily unique
}

Предполагается, чтоdata первоначально идентифицирует объект данных напрямую, но его можно в любой момент законно изменить, чтобы идентифицироватьSharedDataHolder<T> который прямо или косвенно инкапсулирует эквивалентный объект данных. Предположим, что весь код написан для правильной работы (хотя и не обязательно оптимально-эффективного), если любое чтениеdata может произвольно вернуть любое значение, которое когда-либо было записаноdata, но может потерпеть неудачу, если он читаетnull.

декларированиеvolatile Object data будет семантически правильным, но, вероятно, будет налагать дополнительные расходы на каждый последующий доступ к полю. Ввод фиктивной блокировки после первоначальной настройки поля будет работать, но будет слишком медленным. Имея манекенfinal поле, которое объект устанавливает для идентификации себя, казалось бы, оно должно работать; хотя технически я думаю, что может потребоваться, чтобы все обращения к другой области осуществлялись через другую область, я не вижу реалистичного сценария, где это имело бы значение. В любом случае наличие фиктивного поля, целью которого является только обеспечение соответствующей синхронизации посредством его существования, может показаться расточительным.

Есть ли какой-нибудь чистый способ сообщить компилятору, что конкретная запись вdata в конструкторе должно быть отношение «происходит до» в отношении любого чтения этого поля, которое происходит после возврата конструктора (как было бы в случае, если поле былоfinal), без необходимости оплачивать расходы, связанные сvolatileзамки и пр.? В качестве альтернативы, если поток должен был прочитатьdata и найти его нулевым, может ли оно каким-то образом повторить чтение таким образом, чтобы установить «произойдет после» в отношении записиdata [признавая, что такой запрос может быть медленным, но не должен происходить очень часто]?

PS - Если отношения «случается до» не являются транзитивными, будут ли в следующем сценарии правильные отношения «до того» »?

Поток 1 пишет в не финальное полеdat в каком-то объектеFred и сохраняет ссылку на него в конечном полеGeorge.Тема 2 копирует ссылку сGeorge в не финальное полеLarry.Тема 3 читаетLarry.dat.

Из того, что я могу сказать, между записью поля Фреда существует отношение «происходит до того»dat и чтениеGeorge, Будут ли существовать отношения до написания Фреда?dat и чтениеLarry который возвращает ссылку на Фреда, который был скопирован изfinal ссылка наFred? Если нет, есть ли «безопасный» способ скопировать ссылку, содержащуюся вfinal поле в не финальное поле, которое будет доступно через другие потоки?

PPS - если объект и его составляющие никогда не доступны вне потока их создания до тех пор, пока основной конструктор не завершит работу, и последний шаг основного конструктора - сохранить в основном объектеfinal Ссылка на себя, существует ли какая-либо «правдоподобная» реализация / сценарий, где другой поток может увидеть частично построенный объект, независимо от того, использует ли что-нибудь этоfinal ссылка?

Ответы на вопрос(2)

Ваш ответ на вопрос