Является ли статическая инициализированная unmodifiableCollection.get гарантированно неизменной? - PullRequest
6 голосов
/ 15 января 2010

Является ли статическая инициализированная unmodifiableCollection.get гарантированно неизменной?

Для:

статическая финальная карта FOO = Collections.unmodifiableMap (новый HashMap ());

Может ли несколько потоков использовать метод get и не сталкиваться с проблемами?

Даже через элементы в FOO нельзя добавлять / удалять, что мешает методу get манипулировать внутренним состоянием FOO для целей кэширования и т. Д. Если внутреннее состояние каким-либо образом изменено, FOO не может использоваться одновременно. Если это так, то где настоящие неизменяемые коллекции в java?

Ответы [ 6 ]

4 голосов
/ 16 января 2010

С учетом конкретного примера:

static final Map FOO = Collections.unmodifiableMap(new HashMap());

Тогда FOO будет неизменным. Это также никогда не будет иметь никаких элементов. Учитывая более общий случай:

static final Map BAR = Collections.unmodifiableMap(getMap());

Тогда то, является ли это неизменным или нет, полностью зависит от того, сможет ли кто-то еще добраться до базовой Карты и какой это тип Карты. Например, если это LinkedHashMap, то базовый связанный список может быть изменен в соответствии с порядком доступа и может быть изменен путем вызова get (). Самый безопасный способ (используя не параллельные классы) сделать это:

static final Map BAR = Collections.unmodifiableMap(new HashMap(getMap()));

* Javadocs для HashMap подразумевают, что до тех пор, пока вы не вносите никаких структурных изменений в карту, его можно безопасно использовать одновременно, так что это должно быть безопасно для любого из методов доступа, которые вы можете использовать то есть получение различных наборов и итерирование по ним, а затем get () должны быть безопасными.

Если вы можете использовать параллельные классы, то вы также можете сделать:

static final Map BAR = Collections.unmodifiableMap(new ConcurrentHashMap(getMap());

Это будет явно безопасно для использования из нескольких потоков, поскольку ConcurrentHashMap явно безопасен для многопоточного доступа. Внутреннее состояние может быть изменяемым, но внешне видимое состояние не будет, и поскольку класс гарантированно является потокобезопасным, мы можем смело считать его внешне неизменным.

2 голосов
/ 16 января 2010

Рискуя, будто я нахожусь на рекламном празднике, используйте Неизменные коллекции Google и покончите с этим.

0 голосов
/ 15 января 2010

На самом деле хороший вопрос. Подумайте WeakHashMap - это может измениться без вызова операции мутации. LinkedHashMap в режиме порядка доступа практически не отличается.

Документы API для HashMap состояния:

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

Предположительно, это должно быть тогда и только тогда, когда. Это означает, что get не нужно синхронизировать, если HashMap «эффективно неизменяем».

0 голосов
/ 15 января 2010

Неважно, получит ли получатель на возвращенной карте тиддл с каким-то внутренним состоянием, пока объект выполняет свой контракт (который должен быть картой, которую нельзя изменить). Таким образом, ваш вопрос «лай не на то дерево».

Вы правы, проявляя осторожность в отношении UnmodifiableMap, в случае, если у вас нет владения и контроля над картой, которую он оборачивает. Например

Map<String,String> wrapped = new HashMap<String,String>();
wrapped.add("pig","oink");
Map<String,String> wrapper = Collections.unmodifiableMap(wrapped);
System.out.println(wrapper.size());
wrapper.put("cow", "moo"); // throws exception
wrapped.put("cow", "moo");
System.out.println(wrapper.size()); // d'oh!
0 голосов
/ 15 января 2010

В Java SDK нет истинной неизменной карты. Все предлагаемые Карты от Chris являются только безопасными для потоков. Немодифицируемая Карта также не является неизменяемой, поскольку, если базовая Карта изменилась, она также будет ConcurrentModificationException.

Если вы хотите по-настоящему неизменную карту, используйте ImmutableMap из Google Collections / Guava.

0 голосов
/ 15 января 2010

Я бы предложил для любой многопоточной операции использовать ConcurrentHashMap или HashTable, оба они являются поточно-ориентированными.

...