видимость потока карты хэша Java - PullRequest
9 голосов
/ 02 марта 2011

Я полностью загружаю Java HashMap при инициализации, но после инициализации несколько потоков будут считывать данные из HashMap.Я хотел бы избежать любого типа синхронизации, так как карта в основном только для чтения и никогда не меняется.Но могу ли я гарантировать, что все ключи и значения видны всем потокам?

Ответы [ 7 ]

8 голосов
/ 02 марта 2011

Если содержимое карты никогда не меняется, у вас нет проблем.Проблемы с видимостью модели памяти возникают только при изменении содержимого переменной.

Вы, вероятно, захотите синхронизировать инициализацию карты, чтобы убедиться, что никакие потоки не получат к ней доступ до ее полной инициализации, и чтобы убедиться, чточто значения, загруженные в карту, все видны.

РЕДАКТИРОВАТЬ: Первоначально я полностью проигнорировал вопрос о том, как карта инициализируется в первую очередь.После прочтения одной из статей Пью (снова) кажется, что карта действительно должна быть окончательной, чтобы данные инициализации стали видимыми:

Способность видетьправильно составленное значение для поля хорошо, но если само поле является ссылкой, то вы также хотите, чтобы ваш код видел обновленные значения для объекта (или массива), на который оно указывает.Если ваше поле является окончательным, это также гарантировано.Таким образом, вы можете иметь окончательный указатель на массив и не беспокоиться о том, что другие потоки видят правильные значения для ссылки на массив, но неправильные значения для содержимого массива.Опять же, под «правильным» здесь мы подразумеваем «обновленный на конец конструктора объекта», а не «последнее доступное значение».

Существует список условий, которые вызывают отношение «происходит до», приведенный в спецификации Java, я должен привести их здесь (или, если кто-то другой ответит, я проголосую за него).).Статическая переменная и идиома Holder - это, безусловно, один из способов.Вопрос довольно широкий, поскольку в нем не указано, как инициализируется карта. Если вы опубликуете вопрос, описывающий, как вы предлагаете выполнить инициализацию, вы, вероятно, получите более непосредственный полезный ответ.

4 голосов
/ 02 марта 2011

Если у вас есть HashMap, объявленный как final, и вы предварительно инициализировали локальный HashMap, то сохраните глобальный HashMap с локальным, после инициализации конструктора, что содержимое HashMap гарантированно будет видимым.

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

http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf

2 голосов
/ 02 марта 2011

Вам не нужно синхронизировать карту, если все потоки просто читают ее.Чтобы обеспечить неизменность, я бы преобразовал Карту в неизменяемую Карту после инициализации:

map = Collections.unmodifiableMap(map);

Если поток вызывает операцию, которая изменила бы Карту, вместо этого выдается UnsupportedOperationException.

2 голосов
/ 02 марта 2011

Использование ImmutableMap из Гуавы было бы лучшим решением.

1 голос
/ 02 марта 2011

Я думаю, что безопасный способ - объявить его как финальный и инициализировать его в конструкторе: http://www.javamex.com/tutorials/synchronization_final.shtml

0 голосов
/ 02 марта 2011

Это правильный ответ.

Бьюсь об заклад, ваша карта является статическим полем, тогда да, безопасно читать ее без синхронизации.

class SomeClass
    static Map map = init();

Это потому, что JVM выполняет неявную двойную проверку блокировки для инициализации класса.

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

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

0 голосов
/ 02 марта 2011

Пока инициализация завершена до начала чтения, нет никаких причин, по которым все содержимое HashMap не было бы видно каждому потоку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...