У меня есть структура данных, которая состоит из связанных узлов. Вы можете думать об этом как о простом LinkedList. Каждый узел списка состоит из некоторого значения и следующего поля, указывающего на другой узел или null, если он является последним узлом. Первый узел работает как корень, он не имеет значения, он указывает только на следующий узел. Все остальные узлы практически неизменяемы, что когда они не создаются ни их значение, ни их последующее изменение поля в течение жизни, если только структура не размещается, что связано с конкретной ситуацией.изменчивые переменные и барьер памяти в java
Один (только один) поток добавляет новые узлы в начало списка. Это достигается путем создания нового объекта, установки его полей и установки следующего поля на объект, на который указывает корень, а затем установка следующего поля корня в этот новый узел.
Другие узлы просматривают структуру, которая выполняет только чтение. Они имеют ссылку на корневой узел, затем они проходят через другие узлы, пока не найдут то, что ищут или достигнут конца списка.
Мой вопрос: достаточно ли сделать следующее поле нестабильным? Из моего понимания модели Java-памяти, если основной поток (тот, который добавляет новые узлы), будет выполнять изменчивую запись при добавлении нового узла, тогда все будет синхронизировано просто отлично и никаких несоответствий не произойдет.
Также имеет ли право предположить, что при архитектуре x86 изменчивая переменная не приведет к ухудшению производительности? Поскольку другие потоки часто просматривают структуру, читающую следующее поле, важно, чтобы это можно было делать свободно без каких-либо барьеров памяти и т. Д.
У меня также есть еще одна проблема. В потоках, которые будут просматривать структуру, также будут размещены некоторые дополнительные узлы. Эти узлы будут полностью поточно-локальными, и они будут использоваться только потоком, который их создал, и вообще не будут использоваться. Для этих дополнительных узлов нет необходимости в том, чтобы следующее поле было изменчивым. Кроме того, установка изменчивого следующего поля выдает барьер памяти, который приведет к нежелательной потере производительности. Интересно, есть ли способ избежать этого. В идеале это было бы просто идеально, если бы следующее поле работало бы иногда как изменчивое поле, а иногда и как нормальное поле;) или если бы у меня был полный контроль и я мог бы самостоятельно создавать проблемы с памятью, когда мне нужно.
Edit:
Я также хотела бы знать, что можно как-то синхронизировать все эти операции записи на другой изменчивой переменной? Например, какая-то другая совершенно несвязанная статическая переменная? Поскольку волатильная запись сбрасывает все ожидающие записи, не было бы возможным, чтобы следующее поле не было изменчивым, и вместо него будет записана другая изменчивая переменная после того, как поток обновлений выполнит всю работу?
Это не выглядит очень безопасным для меня, так как нет необходимости до отношения, и предыдущие записи могут быть переупорядочены. Следующие назначения полей могут быть повторно обработаны с помощью присвоений полей значений, ведущих к итерации потоков, наблюдающих несогласованное состояние объекта.
Но, может быть, можно придумать такую схему, которая была бы безопасной?Как насчет этого:
Обновление потока сначала создает новый объект, инициализирует его поля значений, устанавливает его следующее поле на узел, на который указывает корневой узел, выполняет изменчивую запись на некоторой статической переменной, устанавливает следующее поле корневой узел для вновь созданного узла
+1. Хорошее объяснение семантики барьера памяти 'volatile', хотя следует отметить, что JVM-модели JSR133 (т. Е. Java <5.0) не имели одинаковой семантики ... – thkala
Хорошая точка для включения в качестве примечания. –
Спасибо за отличный ответ. Надеюсь, вы хорошо поняли, что происходит в моем коде. Нет корневой ссылки, только корневой узел. Вот почему я установил два разных следующих поля (один из нового объекта и один из корневого узла). – ciamej