We always have a phone book all the Friends of the phone, but, if a friend often contact, those friends of the phone number of the phone book we can remember, but, if long time has not been contacted, to contact the friend again, we have to ask for the phone book, but, Searching by phone book is still time-consuming. However, what our brains can remember is certain, and we can only remember what we are most familiar with, and the long-time unfamiliar nature forgets.
In fact, the computer also used the same concept, we use the cache to store the previously read data, rather than throw it away, so that, again read, you can directly in the cache, and do not have to re-search again, so that the system's response capacity will be greatly improved. However, when we read a very large number of times, we can not put all the data that has been read in the cache, after all, memory size is certain, we generally put the most recently read in the cache (the equivalent of our recently contacted friend's name and phone in the brain). Now we're going to look at such a caching mechanism.
LRU Cache:
The LRU cache takes advantage of such an idea. LRU is the abbreviation for least recently used, which translates to "least recently used", that is, the LRU cache removes the least recently used data for the most recent data read. And the most often read, but also the most read, so, using the LRU cache, we can improve the system performance.
Realize:
To implement an LRU cache, we first use a class Linkedhashmap. There are two advantages to using this class: one is that it has already implemented the storage in order of access, that is, the most recently read will be placed in the front, the most infrequently read will be placed at the end (of course, it can also be implemented in the order of insertion in the storage). Second, Linkedhashmap itself has a method to determine if the least frequently read number needs to be removed, but the original method does not need to be removed by default (this is, Linkedhashmap is equivalent to a linkedlist), so we need to override such a method , so that when the number of data stored in the cache exceeds the specified number, the most infrequently used removal. Linkedhashmap API written very clearly, recommend you can read it first.
To implement the LRU cache based on Linkedhashmap, we can choose inheritance or delegation, I prefer delegation. Based on the implementation of delegation has been written, and written very beautiful, I will not swim. The code is as follows:
package lru;import java.util.linkedhashmap;import java.util.collection;import java.util.map;import java.util.arraylist;/** * an lru cache, based on <code>LinkedHashMap</code>. * * <p> * This cache has a fixed maximum number of elements (<code>cacheSize</code>) . * if the cache is full and another entry is added, the LRU (least recently * used) entry is dropped. * * <p> * this class is thread-safe. all methods of this class are synchronized. * * <p> * Author: Christian d ' heureuse, inventec informatik ag, zurich, switzerland<br> * multi-licensed: epl&Nbsp;/ lgpl / gpl / al / bsd. */public class lrucache<k, v> {private static final float hashtableloadfactor = 0.75f;private linkedhashmap<k, v> map;private int cachesize;/** * creates a new LRU cache. * * @param cacheSize * the maximum number of entries that will be kept in this cache. */public lrucache (Int cacheSize) {this.cacheSize = cacheSize;int hashTableCapacity = (int) math.ceil ( Cachesize / hashtableloadfactor) + 1;map = new linkedhashmap<k, v > (hashtablecapacity, hashtableloadfactor,true) {// (An anonymous inner class) Private static final long serialVersionUID = 1; @Overrideprotected boolean removeeldestentry ( map.entry<k, v> eldest) {return size () > lrucache.this.cachesize;};} /** * retrieves an entry from the cache.<br> * the retrieved entry becomes the mru (most recently used) entry. * * @param key * the key whose associated value is to be returned. * @ return the value associated to this key, or null if no Value with this * key exists in the cache. */public synchronized v get (K key) {return map.get ( key);} /** * adds an entry to this cache. The new entry becomes the MRU ( most recently * used) entry. if an entry with the specified key already exists in the * cache, it is replaced by the new entry. If the cache is full, the LRU * ( least recently used) entry is removed from the cache. * * @param key * the key with which the specified value is to be associated. * @param value * a value to be associated with the specified key. */public synchronized void p ut (k key, v value) {map.put (key, value);} /** * clears the cache. */public synchronized void clear () { Map.clear ();} /** * returns the number of used entries in the cache. * * @return the number of entries currently in the Cache. */public synchronized int usedentries () {return map.size ();} /** * returns a <code>collection</code> that contains a copy of all cache * entries. * * @return a <code >collection</code> with a copy of the cache content. */public synchronized collection<map.entry<k, v>> getall () {return new Arraylist<map.entry<k, v>> (Map.entryset ());} PublIc static void main (String[] args) {lrucache<string, string> c = new LRUCache<String, String> (3); C.put ("1", "one"); // 1c.put ("2", " // 2 1c.put ("3", "three") // 3 2 1c.put ("4", "four"); // 4 3 2if (C.get ("2") == null) Throw new error (); // 2 4 3c.put ("5", "Five") // 5 2 4c.put ("4", "Second four"); / / 4 5 2c.put ("4", "Second four"); // 4 5 2c.put ("4", "second four "); // 4 5 2c.put (" 4 ", " Second four "); // 4 5 2// Verify cache content.//if (C.usedentries () != 3)//throw new error (); if (!c.get ("4"). Equals ("Second four")) Throw new error ();if (!c.get ("5"). Equals ("Five" )) throw new  Error ();if (!c.get ("2"). Equals ("both")) Throw new error ();// list cache content.for (Map.entry<string, string> e : c.getall ()) {System.out.println (E.getkey () + " : " + e.getvalue ());}}
code derived from:http://www.source-code.biz/snippets/java/6.htm
In the blog http://gogole.iteye.com/blog/692103, the author uses a doubly linked list + hashtable approach. If in the interview question how to implement LRU, the examiner will generally require the use of double-linked list + hashtable way. So, I excerpt the original part of the text as follows:
Double linked list + Hashtable implementation principle:
All caches are connected by a double-connected table, and when a position is hit, it is adjusted to the linked list by adjusting the point of the linked list, and the newly added cache is added directly to the list header. In this way, after several cache operations, the most recently hit, will be moved to the head of the chain, without hitting, and want to move behind the list, the end of the list is the least recently used cache. When you need to replace the content, the last position of the list is the least hit position, we only need to eliminate the last part of the list.
package lru;import java.util.hashtable;public class lrucached {private int cachesize;private hashtable<object, entry> nodes;//Cache Container private int currentsize; private entry first;//chain head private entry last;//chain footer public lrucached (int i) { Currentsize = 0;cachesize = i;nodes = new hashtable<object, entry > (i);//cache container}/** * Gets the object in the cache and puts it on the front */public entry get (object key) {entry node = nodes.get (Key);if (node != null) {movetohead (node); Return node ;} else {return null;}} /** * add entry to hashtable, and put Entry */public void put (Object key, object value) {//First see if the Hashtable exists the entry, if present, update only its valueentry node = Nodes.get (Key);if (node == null) {//cache container has exceeded size .if (CURRENTSIZE&Nbsp;>= cachesize) {nodes.remove (Last.key); Removelast ();} else {currentsize++;} Node = new entry ();} node.value = value;//the most recently used node to the list header, indicating the latest used. Movetohead (node); Nodes.put (Key, node); /** * Remove Entry, Note: The delete operation will be executed only if the cache is full */public void remove (Object key) {entry node = nodes.get (key);//delete if (node != null) in the list {if ( Node.prev != null) {node.prev.next = node.next;} if (Node.next != null) {node.next.prev = node.prev;} if (Last == node) last = node.prev;if (First == node) first = Node.next;} Delete Nodes.remove (key) in Hashtable;} /** * Delete the tail node of the linked list, even with the last used Entry */private void removelast () {//the end of the list is not empty, Then point the end of the list to null. delete the footer (delete the least used cache object) if (last != null) {if (last.prev != NULL) Last.prev.next = nulL;elsefirst = null;last = last.prev;}} /** * moves to the list header, indicating that this node is the most recently used */private void movetohead (Entry node) {if ( Node == first) return;if (node.prev != null) node.prev.next = node.next;if (Node.next != null) node.next.prev = node.prev;if (Last == node) Last = node.prev;if (first != null) {node.next = first;first.prev = node;} first = node;node.prev = null;if (Last == null) Last = first;} /* * empty Cache */public void clear () {first = null;last = null; currentsize = 0;}} class entry {entry prev;//previous node entry next;//object value;//value object key;//key}
LRU Cache Introduction and implementation (Java)