code_junkie

How would you implement an LRU cache in Java 6?

Nov 11th, 2011
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.29 KB | None | 0 0
  1. private class LruCache<A, B> extends LinkedHashMap<A, B> {
  2. private final int maxEntries;
  3.  
  4. public LruCache(final int maxEntries) {
  5. super(maxEntries + 1, 1.0f, true);
  6. this.maxEntries = maxEntries;
  7. }
  8.  
  9. /**
  10. * Returns <tt>true</tt> if this <code>LruCache</code> has more entries than the maximum specified when it was
  11. * created.
  12. *
  13. * <p>
  14. * This method <em>does not</em> modify the underlying <code>Map</code>; it relies on the implementation of
  15. * <code>LinkedHashMap</code> to do that, but that behavior is documented in the JavaDoc for
  16. * <code>LinkedHashMap</code>.
  17. * </p>
  18. *
  19. * @param eldest
  20. * the <code>Entry</code> in question; this implementation doesn't care what it is, since the
  21. * implementation is only dependent on the size of the cache
  22. * @return <tt>true</tt> if the oldest
  23. * @see java.util.LinkedHashMap#removeEldestEntry(Map.Entry)
  24. */
  25. @Override
  26. protected boolean removeEldestEntry(final Map.Entry<A, B> eldest) {
  27. return super.size() > maxEntries;
  28. }
  29. }
  30.  
  31. Map<String, String> example = Collections.synchronizedMap(new LruCache<String, String>(CACHE_SIZE));
  32.  
  33. class CacheElement {
  34. private final Object obj;
  35. private int numberOfUsers = 0;
  36.  
  37. CacheElement(Object obj) {
  38. this.obj = obj;
  39. }
  40.  
  41. ... etc.
  42. }
  43.  
  44. public class ConcurrentLRUCache<Key, Value> {
  45.  
  46. private final int maxSize;
  47.  
  48. private ConcurrentHashMap<Key, Value> map;
  49. private ConcurrentLinkedQueue<Key> queue;
  50.  
  51. public ConcurrentLRUCache(final int maxSize) {
  52. this.maxSize = maxSize;
  53. map = new ConcurrentHashMap<Key, Value>(maxSize);
  54. queue = new ConcurrentLinkedQueue<Key>();
  55. }
  56.  
  57. /**
  58. * @param key - may not be null!
  59. * @param value - may not be null!
  60. */
  61. public void put(final Key key, final Value value) {
  62. if (map.containsKey(key)) {
  63. queue.remove(key); // remove the key from the FIFO queue
  64. }
  65.  
  66. while (queue.size() >= maxSize) {
  67. Key oldestKey = queue.poll();
  68. if (null != oldestKey) {
  69. map.remove(oldestKey);
  70. }
  71. }
  72. queue.add(key);
  73. map.put(key, value);
  74. }
  75.  
  76. /**
  77. * @param key - may not be null!
  78. * @return the value associated to the given key or null
  79. */
  80. public Value get(final Key key) {
  81. return map.get(key);
  82. }
  83.  
  84. import java.util.HashMap;
  85. import java.util.Map;
  86. public class LRUCache<K, V>
  87. {
  88. int maxSize;
  89. int currentSize = 0;
  90.  
  91. Map<K, ValueHolder<K, V>> map;
  92. LinkedList<K> queue;
  93.  
  94. public LRUCache(int maxSize)
  95. {
  96. this.maxSize = maxSize;
  97. map = new HashMap<K, ValueHolder<K, V>>();
  98. queue = new LinkedList<K>();
  99. }
  100.  
  101. private void freeSpace()
  102. {
  103. K k = queue.remove();
  104. map.remove(k);
  105. currentSize--;
  106. }
  107.  
  108. public void put(K key, V val)
  109. {
  110. while(currentSize >= maxSize)
  111. {
  112. freeSpace();
  113. }
  114. if(map.containsKey(key))
  115. {//just heat up that item
  116. get(key);
  117. return;
  118. }
  119. ListNode<K> ln = queue.add(key);
  120. ValueHolder<K, V> rv = new ValueHolder<K, V>(val, ln);
  121. map.put(key, rv);
  122. currentSize++;
  123. }
  124.  
  125. public V get(K key)
  126. {
  127. ValueHolder<K, V> rv = map.get(key);
  128. if(rv == null) return null;
  129. queue.remove(rv.queueLocation);
  130. rv.queueLocation = queue.add(key);//this ensures that each item has only one copy of the key in the queue
  131. return rv.value;
  132. }
  133. }
  134.  
  135. class ListNode<K>
  136. {
  137. ListNode<K> prev;
  138. ListNode<K> next;
  139. K value;
  140. public ListNode(K v)
  141. {
  142. value = v;
  143. prev = null;
  144. next = null;
  145. }
  146. }
  147.  
  148. class ValueHolder<K,V>
  149. {
  150. V value;
  151. ListNode<K> queueLocation;
  152. public ValueHolder(V value, ListNode<K> ql)
  153. {
  154. this.value = value;
  155. this.queueLocation = ql;
  156. }
  157. }
  158.  
  159. class LinkedList<K>
  160. {
  161. ListNode<K> head = null;
  162. ListNode<K> tail = null;
  163.  
  164. public ListNode<K> add(K v)
  165. {
  166. if(head == null)
  167. {
  168. assert(tail == null);
  169. head = tail = new ListNode<K>(v);
  170. }
  171. else
  172. {
  173. tail.next = new ListNode<K>(v);
  174. tail.next.prev = tail;
  175. tail = tail.next;
  176. if(tail.prev == null)
  177. {
  178. tail.prev = head;
  179. head.next = tail;
  180. }
  181. }
  182. return tail;
  183. }
  184.  
  185. public K remove()
  186. {
  187. if(head == null)
  188. return null;
  189. K val = head.value;
  190. if(head.next == null)
  191. {
  192. head = null;
  193. tail = null;
  194. }
  195. else
  196. {
  197. head = head.next;
  198. head.prev = null;
  199. }
  200. return val;
  201. }
  202.  
  203. public void remove(ListNode<K> ln)
  204. {
  205. ListNode<K> prev = ln.prev;
  206. ListNode<K> next = ln.next;
  207. if(prev == null)
  208. {
  209. head = next;
  210. }
  211. else
  212. {
  213. prev.next = next;
  214. }
  215. if(next == null)
  216. {
  217. tail = prev;
  218. }
  219. else
  220. {
  221. next.prev = prev;
  222. }
  223. }
  224. }
  225.  
  226. private void moveToFront(int index) {
  227. if (listHead != index) {
  228. int thisNext = nextElement[index];
  229. int thisPrev = prevElement[index];
  230. nextElement[thisPrev] = thisNext;
  231. if (thisNext >= 0) {
  232. prevElement[thisNext] = thisPrev;
  233. } else {
  234. listTail = thisPrev;
  235. }
  236. //old listHead and new listHead say new is 1 and old was 0 then prev[1]= 1 is the head now so no previ so -1
  237. // prev[0 old head] = new head right ; next[new head] = old head
  238. prevElement[index] = -1;
  239. nextElement[index] = listHead;
  240. prevElement[listHead] = index;
  241. listHead = index;
  242. }
  243. }
  244.  
  245. package util.collection;
  246.  
  247. private final int maxSize;
  248. private int currentSize = 0;
  249.  
  250. private ConcurrentHashMap<Key, Value> map;
  251. private ConcurrentLinkedQueue<Key> queue;
  252.  
  253. public ConcurrentLRUCache(final int maxSize) {
  254. this.maxSize = maxSize;
  255. map = new ConcurrentHashMap<Key, Value>(maxSize);
  256. queue = new ConcurrentLinkedQueue<Key>();
  257. }
  258.  
  259. private synchronized void freeSpace() {
  260. Key key = queue.poll();
  261. if (null != key) {
  262. map.remove(key);
  263. currentSize = map.size();
  264. }
  265. }
  266.  
  267. public void put(Key key, Value val) {
  268. if (map.containsKey(key)) {// just heat up that item
  269. put(key, val);
  270. return;
  271. }
  272. while (currentSize >= maxSize) {
  273. freeSpace();
  274. }
  275. synchronized(this) {
  276. queue.add(key);
  277. map.put(key, val);
  278. currentSize++;
  279. }
  280. }
  281.  
  282. public Value get(Key key) {
  283. return map.get(key);
  284. }
Add Comment
Please, Sign In to add comment