У меня есть структура данных, которая состоит из связанных узлов. Вы можете думать об этом как о простом LinkedList. Каждый узел списка состоит из некоторого значения и следующего поля, указывающего другой узел или ноль, если это последний узел. Первый узел работает как корень, он не имеет значения, он только указывает на следующий узел. Все остальные узлы практически неизменны, то есть после их создания ни их значение, ни их следующее поле не изменяются в течение срока службы, если только структура не располагается, что относится к конкретной ситуации.
Один (только один) поток добавляет новые узлы в начало списка. Это достигается путем создания нового объекта, установки его полей и установки следующего поля для объекта, указанного корнем, а затем установки следующего поля корня для этого нового узла.
Другие узлы просматривают структуру, только выполняя операции чтения. У них есть ссылка на корневой узел, затем они проходят через другие узлы, пока не найдут то, что ищут, или не достигнут конца списка.
Мой вопрос: достаточно ли сделать следующее поле нестабильным? Из моего понимания модели памяти Java, если основной поток (тот, который добавляет новые узлы) будет выполнять энергозависимую запись при добавлении нового узла, тогда все будет синхронизироваться просто отлично, и никаких несоответствий не будет.
Также правильно ли предполагать, что в архитектуре x86 чтение изменчивой переменной не повлечет за собой снижения производительности? Поскольку другие потоки будут часто просматривать структуру, читая следующее поле, важно, чтобы это можно было делать свободно, без каких-либо барьеров памяти и т. Д.
У меня также есть еще одна проблема. Потоки, которые будут просматривать структуру, также будут содержать некоторые дополнительные узлы. Эти узлы будут полностью локальными для потока, то есть они будут использоваться только тем потоком, который их создал, и не будут использоваться совместно.
Для этих дополнительных узлов нет необходимости, чтобы следующее поле было изменчивым. Более того, установка поля volatile next создаст барьер памяти, который приведет к нежелательной потере производительности.
Интересно, есть ли способ избежать этого. В идеале было бы идеально, если бы следующее поле работало иногда как изменчивое поле, а иногда как обычное поле;) или если бы я имел полный контроль и мог самостоятельно создавать барьеры памяти, когда мне это нужно.
Изменить:
Мне также было интересно, можно ли как-то синхронизировать все эти записи в другой переменной volatile? Например, какая-то другая совершенно не связанная статическая переменная? Поскольку volatile запись сбрасывает все ожидающие записи, не будет ли возможно, чтобы следующее поле не было volatile, и вместо этого другая переменная переменная будет записана после того, как поток обновления выполнит всю работу?
Для меня это выглядит не очень безопасно, так как ничего не происходит до того, как отношения и предыдущие записи могут быть переупорядочены. Следующие назначения полей могут быть переупорядочены с помощью назначений полей значений, приводящих к итерированию потоков, наблюдающих несогласованное состояние объекта.
Но, возможно, можно придумать такую схему, которая была бы безопасной? Как насчет этого:
обновляющий поток сначала создает новый объект, инициализирует его поля значений, устанавливает свое следующее поле равным узлу, указанному корневым узлом, выполняет энергозависимую запись в некоторую статическую переменную , устанавливает следующее поле корня узел к вновь созданному узлу