WeakHashMap итерация и сборка мусора - PullRequest
14 голосов
/ 19 мая 2010

Я использую WeaekHashMap для реализации кэша. Мне интересно, перебираю ли я ключи этой карты, и в то же время сборщик мусора активно удаляет ключи с этой карты, получу ли я ConcurrentModificationException? Я так не думаю, потому что, насколько я понимаю, исключение одновременной модификации происходит из-за ошибок в коде приложения, из-за которых разработчик забыл понять, что эта же карта используется / используется другими потоками, и в этом случае этого не должно происходить. Но интересно, как JVM справится с этим, когда WeakHashMap не синхронизируется?

Ответы [ 4 ]

12 голосов
/ 19 мая 2010

Как сказал bkail, когда GC "удаляет" запись из WeakHashMap, это не приведет к одновременной модификации. В действительности, GC собирает лежащий в основе объект, поскольку существует жесткая ссылка на сам объект WeakReference (который содержит реальный ключ). Поэтому реальный объект (эталонный объект), на который непосредственно ссылается карта, не собирается, поэтому карта не изменяется до тех пор, пока один из ваших потоков не вызовет метод на этой карте. В это время карта проверяет эталонную очередь из ГХ и находит все ключи, которые были собраны, и удаляет их с карты - поэтому фактические изменения в структуре карты происходят в одном из ваших потоков.

Если подумать об этом, то может быть один случай, когда вы можете получить параллельную модификацию в такой карте, которую вы не получите в карте другого типа - если вы поместите ключ, который уже существует, или вызовете метод получения. Но на самом деле в параллельном приложении вы должны в любом случае блокировать эти вызовы, чтобы в вашей программе была действительно одновременная ошибка доступа.

Как говорится в ответе на ваш вопрос, вы действительно не должны использовать WeakHashMap для кэша (даже если вы говорили о ключах кэширования). В кеше вы не хотите, чтобы ваши значения «магически» исчезали, когда на значения больше нет ссылок. Обычно вы хотите, чтобы они исчезали, когда существует определенное максимальное число (что-то вроде коллекций Apache LRUMap) или освобождается по требованию памяти.

В дальнейшем вы можете использовать карту с SoftReference (коллекции Apache предоставляют ReferenceMap, который позволяет вам указать тип ссылки для ключа или значения). Мягкая ссылка указывается, чтобы быть выпущенной только на основе давления памяти - слабая ссылка, с другой стороны, должна делать больше с GC, признающим, что нет жесткой ссылки, остающейся к объекту, и может освободить ее в любое время. Конечно, то, как мягкая ссылка действительно работает, также зависит от реализации JVM.

РЕДАКТИРОВАТЬ : Я перечитал ваш вопрос и хочу затронуть еще один момент. Поскольку фактические изменения происходят с внутренними структурами WeakHashMap в вашем собственном потоке, , если вы используете эту карту только в одном потоке, вам не нужно синхронизировать какие-либо вызовы методов . Это поведение ничем не отличается от любого другого Map.

5 голосов
/ 19 мая 2010

Нет, вы не получите ConcurrentModificationException. WeakHashMap использует ReferenceQueue.poll при вызове различных операций. Другими словами, каждый абонент молча отвечает за удаление устаревших записей с карты. Однако это означает, что небезопасно вызывать методы в WeakHashMap из нескольких потоков, которые в противном случае выглядели бы «только для чтения», поскольку любой вызов get () может уничтожить связанный список записей, который другой поток пытается выполнить .

0 голосов
/ 19 мая 2010

Документация не совсем ясна по этому вопросу, но она говорит это:

Поведение класса WeakHashMap частично зависит от действий сборщик мусора, так что несколько знакомая (хотя и не обязательная) карта инварианты не выполняются для этого класса. Потому что сборщик мусора может отменить ключи в любое время, WeakHashMap может вести себя как неизвестная тема молча удаляет записи . В частности, даже если вы синхронизировать на экземпляре WeakHashMap и не вызывать ни одного из его мутатора методы, можно по размеру метод для возврата меньших значений время для возврата метода isEmpty ложь, а затем правда, для Метод содержит ключ для возврата истины и позже false для данного ключа, для получить метод, чтобы вернуть значение для данный ключ, но позже вернуть ноль, для метод put для возврата null и удалить метод, чтобы вернуть ложь для ключ, который ранее казался в карта, и для последующих проверки набора ключей, значение установить, а запись установить для выхода последовательно меньшее количество элементы. - Java API

Я думаю, что, учитывая это описание, вы должны ожидать время от времени получать ConcurrentModificationException s при повторении карты. Я бы разработал ваш кеш так, чтобы вы выполняли как можно меньше итераций.

0 голосов
/ 19 мая 2010

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

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