Итерация и сборка мусора WeakHashMap
Я использую WeaekHashMap
для реализации кэша. Мне интересно, если я повторяю ключи этой карты, и в то же время сборщик мусора активно удаляет ключи с этой карты, получаю ли я ConcurrentModificationException
?
Я так не думаю, потому что, насколько я понимаю, параллельное моделирование возникает из-за ошибок в коде приложения, где разработчик забыл понять, что одна и та же карта используется совместно/используется другими потоками, и в этом случае этого не должно произойти. Но интересно, как JVM справится с этим, когда WeakHashMap не синхронизируется?
Ответы
Ответ 1
Как сказал bkail, когда GC "удаляет" запись из WeakHashMap
, она не будет вызывать параллельную модификацию. На самом деле GC собирает базовый объект, поскольку существует жесткая ссылка на объект WeakReference
(который содержит реальный ключ). Поэтому реальный объект (ссылочный объект), который напрямую ссылается на карту, не собирается, поэтому карта не изменяется, пока один из ваших потоков не вызовет метод на этой карте. В это время карта проверяет опорную очередь из GC и находит все ключи, которые были собраны, и удаляет их с карты - поэтому фактические изменения в структуре карты происходят в одном из ваших потоков.
Если вы думаете об этом, тогда может быть один случай, когда вы можете получить параллельную модификацию на такой карте, которую вы бы не получили в другой карте - если вы поместите ключ, который уже существует или вызывается методом getter. Но на самом деле, в параллельном приложении вы должны блокировать все эти вызовы, так что у вас будет ошибка с одновременным доступом в вашей программе.
В ответ на ваш вопрос вы действительно не должны использовать WeakHashMap
для кеша (даже если вы говорили о кешировании ключей). В кеше вы не хотите, чтобы ваши значения "магически" исчезали, когда значения больше не ссылаются. Как правило, вы хотите, чтобы они исчезли, когда есть определенное максимальное количество (что-то вроде коллекций Apache LRUMap
) или выпущено по требованию памяти.
Для более поздних версий вы можете использовать карту с SoftReference
(коллекции Apache предоставляют ReferenceMap
, что позволяет вам указать вид ссылки для ключа или значения). Мягкая ссылка указана только для освобождения на основе давления памяти - с другой стороны, слабая ссылка должна делать больше с GC, признающим, что на объекте нет твердой ссылки, и она может отпустить ее в любое время. Конечно, как работает мягкая ссылка, также зависит от реализации JVM.
РЕДАКТИРОВАТЬ. Я перечитываю ваш вопрос и хочу обратиться к другому вопросу. Поскольку фактические изменения происходят с внутренними структурами WeakHashMap
в вашем собственном потоке, если вы используете эту карту только в одном потоке, вам не нужно синхронизировать вызовы методов. Это поведение не отличается от любого другого Map
.
Ответ 2
Нет, вы не получите ConcurrentModificationException. WeakHashMap использует ReferenceQueue.poll, когда вы вызываете различные операции. Другими словами, каждый вызывающий абонент молча отвечает за очистку устаревших записей от Карты. Однако это означает, что небезопасно вызывать методы на WeakHashMap из нескольких потоков, которые иначе выглядели бы "только для чтения", потому что любой вызов метода get() может уничтожить связанный с записью список, который другой поток пытается итерации.
Ответ 3
WeakHashMap слаб на клавишах, а не на значениях, поэтому он не подходит для кеша значений, если вы хотите освободить место, когда значение не используется. Вы можете взглянуть на MapMaker из google коллекции.
Ответ 4
Документация не совсем ясно говорит об этом, но она говорит следующее:
Поведение класса WeakHashMap частично зависит от действий сборщик мусора, поэтому несколько знакомый (хотя и не обязательно) Карта инварианты для этого класса не выполняются. Потому что сборщик мусора может отказаться от ключей в любое время, WeakHashMap может вести себя так, как будто неизвестная нить молча удаляет Записи. В частности, даже если вы синхронизировать в экземпляре WeakHashMap и не ссылаются ни на один из его мутаторов методов, возможно размер метод для возврата меньших значений время, для возврата метода isEmpty false, а затем true, для содержит методKey для возврата true и позже false для данного ключа, для получить метод для возврата значения для данный ключ, но позже возвращает null, для метод put возвращает null и удалить метод для возврата false для ключ, который ранее оказался в карты и для последовательных экзамены по набору ключей, значение set, и запись, установленная для получения последовательно меньшее количество элементы. - Java API
Я думаю, что с учетом этого описания вы должны иногда получать ConcurrentModificationException
при повторении карты. Я бы разработал ваш кеш, чтобы сделать как можно меньше итераций.