Для памяти, известно, кэш, вы можете использовать Apache Commons collections, в частности, их org.apache.commons.collections.map.ReferenceMap
класс. Специальная операция Java - soft reference.Java предоставляет WeakHashMap
для слабых ссылок, но слабые ссылки - это не то, что вы хотите для кеша. Java не предоставляет SoftHashMap
, но ReferenceMap
от Apache Commons может быть работоспособной заменой.
Память об использовании мягких ссылок несколько грубая и негибкая. Вы можете играть с некоторыми вариантами Java, чтобы каким-то образом настроить их, особенно значение -XX:SoftRefLRUPolicyMSPerMB
, которое выражает (в миллисекундах), как долго сохраняются в памяти сохраненные значения софт-ссылкой (когда они перестают быть непосредственно доступными). Например, с этим:
java -XX:SoftRefLRUPolicyMSPerMB=2500
то JVM будет пытаться сохранить в кэше значение на 2,5 секунды больше, чем то, что он сделал бы с WeakHashMap
.
Если мягкие ссылки не предоставляют то, что вы ищете, тогда вам придется реализовать свою собственную стратегию кэширования и, действительно, сбросить карту вручную. Это ваш первоначальный вопрос. Для промывки вы можете использовать метод clear()
или просто создать новый HashMap
. Разница должна быть небольшой, и у вас могут даже возникнуть проблемы измерение эта разница.
Переключение между «полным кешем» и «пустым кешем» также может считаться немного грубым, поэтому вы можете поддерживать несколько карт. Например, вы поддерживаете десять карт. Когда вы ищете кешированное значение, вы смотрите на все карты, но когда у вас есть значение, вы помещаете его только в первую карту. Когда вы хотите сбросить карты, вы поворачиваете карты: первая карта становится второй, вторая становится третьей и т. Д., Вплоть до десятой карты, которая отбрасывается. Создается новая свежая первая карта. Это будет выглядеть так:
import java.util.*;
public class Cache {
private static final int MAX_SIZE = 500000;
private Map[] backend;
private int size = 0;
public Cache(int n)
{
backend = new Map[n];
for (int i = 0; i < n; i ++)
backend[i] = new HashMap();
}
public int size()
{
return size;
}
public Object get(Object key)
{
for (Map m : backend) {
if (m.containsKey(key))
return m.get(key);
}
return null;
}
public Object put(Object key, Object value)
{
if (backend[0].containsKey(key))
return backend[0].put(key, value);
int n = backend.length;
for (int i = 1; i < n; i ++) {
Map m = backend[i];
if (m.containsKey(key)) {
Object old = m.remove(key);
backend[0].put(key, value);
return old;
}
}
backend[0].put(key, value);
size ++;
while (size > MAX_SIZE) {
size -= backend[n - 1].size();
System.arraycopy(backend, 0, backend, 1, n - 1);
backend[0] = new HashMap();
}
return null;
}
}
Код, указанный выше, полностью не проверен и должен быть дополнен дженериками. Тем не менее, он иллюстрирует основные идеи: все карты проверяются при чтении (get()
), все новые значения переходят на первую карту, общий размер поддерживается, а когда размер превышает заданный предел, карты вращаются. Обратите внимание, что есть специальное лечение, когда новое значение задается для известного ключа. Кроме того, в этой версии ничего не делается при поиске кешированного значения, но мы могли бы «омолодить» доступное кешированное значение: при get()
, когда значение найдено, но не на первой карте, его можно перенести на первую карту. Таким образом, часто используемые значения будут сохраняться навсегда.
WeakHashMap работает с идентификатором объекта. Не уверен, что это будет полезно с длинными ключами. – Thilo
Да, я упомянул об этом сомнении и в своем посте. – polygenelubricants