Изменение порядка ввода LRUCache при использовании get
Я проверил официальную документацию Android для LRUCache, которая гласит : Каждый раз, когда значение обращается, оно перемещается в начало очереди. Когда значение добавляется в полный кэш, значение в конце этой очереди удаляется и может стать пригодным для сборки мусора . Я полагаю, что это двусвязный список, который поддерживается linkedhashmap, который используется кэшем. Чтобы проверить это поведение, я проверил исходный код LruCache и проверил get (K ключ) метод. Далее он вызывает метод get map, который получает значение из базового hashmap и вызывает метод recordAccess.
public V get(Object key) {
LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
Метод RecordAccess, в свою очередь, перемещает доступную запись в конец списка, если accessOrder установлен в true (для моей задачи предположим, что это так), иначе он ничего не делает.
/**
* This method is invoked by the superclass whenever the value
* of a pre-existing entry is read by Map.get or modified by Map.set.
* If the enclosing Map is access-ordered, it moves the entry
* to the end of the list; otherwise, it does nothing.
*/
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header);
}
}
Это звучит противоречащим приведенному выше утверждению, где говорится, что элемент перемещается в начало очереди. Вместо этого он перешел к последнему элемент списка (с помощью head.до). Конечно, я что-то упускаю, какая-нибудь помощь?
2 ответа:
Вы ничего не упускаете, просто Вы читаете
LruCache
документацию дляLinkedHashMap
.LinkedHashMap
имеет свою собственную документацию, в частности о своемaccessOrder
. (То же самое на Java docs).[...когда accessOrder=true...] порядок итерации - это порядок, в котором его записи были доступны в последний раз, от наименее недавно доступного до самого последнего (порядок доступа)
Таким образом,
LinkedHashMap
помещает последние использованные записи в конец, и это зарегистрированный.Практически
LruCache
описывает, как такой кэш работает в теории, ноLinkedHashMap
показывает, как реализовать его без добавления отдельных итераторов с обратным движением: помещая последние элементы в конец, обрезка может использовать уже имеющийся итератор (с прямым движением) для эффективного доступа (и удаления) старых элементов.Хотя здесь и сейчас я не мог сказать, что было не так.
removeEldestEntry
. Возможно, в прошлом его не существовало.
Из явадока
LinkedHashMap
:Если используется конструктор с тремя аргументами и accessOrder задается как true, итерация будет выполняться в том порядке, в котором были получены записи. На порядок доступа влияет put, get и putAll операции, но не операции над представлениями коллекции.
Именно тот случай , который имеет
LruCache
.Давайте посмотрим, что делаетpublic LruCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; this.map = new LinkedHashMap<K, V>(0, 0.75f, true); }
recordAccess()
:void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) { // true, because `LruCache` instantiated this // map with `accessOrder = true` lm.modCount++; remove(); // remove this `LinkedHashMapEntry` from the map addBefore(lm.header); // adds this entry before the current header of // the map, thus this entry becomes the header } }
Вместо этого он перемещается в последний элемент списка (используя head.до).
Я не могу видеть, как ваше заявление является действительным.