基于 LinkedHashMap 的 LRU 算法实现

  1. public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
  2. private final int maxCapacity;
  3. private static final float DEFAULT_LOAD_FACTOR = 0.75f;
  4. private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
  5. private final Lock rLock = rwLock.readLock();
  6. private final Lock wLock = rwLock.writeLock();
  7. public LRULinkedHashMap(int maxCapacity) {
  8. super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
  9. this.maxCapacity = maxCapacity;
  10. }
  11. /** LRU 核心 */
  12. @Override
  13. protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
  14. rLock.lock();
  15. try {
  16. return size() > maxCapacity;
  17. } finally {
  18. rLock.unlock();
  19. }
  20. }
  21. @Override
  22. public boolean containsKey(Object key) {
  23. rLock.lock();
  24. try {
  25. return super.containsKey(key);
  26. } finally {
  27. rLock.unlock();
  28. }
  29. }
  30. @Override
  31. public V get(Object key) {
  32. rLock.lock();
  33. try {
  34. return super.get(key);
  35. } finally {
  36. rLock.unlock();
  37. }
  38. }
  39. @Override
  40. public V put(K key, V value) {
  41. wLock.lock();
  42. try {
  43. return super.put(key, value);
  44. } finally {
  45. wLock.unlock();
  46. }
  47. }
  48. @Override
  49. public int size() {
  50. rLock.lock();
  51. try {
  52. return super.size();
  53. } finally {
  54. rLock.unlock();
  55. }
  56. }
  57. @Override
  58. public void clear() {
  59. rLock.lock();
  60. try {
  61. super.clear();
  62. } finally {
  63. rLock.unlock();
  64. }
  65. }
  66. public ArrayList<Map.Entry<K, V>> getAll() {
  67. rLock.lock();
  68. try {
  69. return new ArrayList<>(super.entrySet());
  70. } finally {
  71. rLock.unlock();
  72. }
  73. }
  74. }
  1. class LruCache<T> implements Serializable {
  2. private static final long serialVersionUID = 1L;
  3. // Although the internal implementation uses a Map, this cache
  4. // implementation is only concerned with the keys.
  5. private final Map<T,T> cache;
  6. public LruCache(final int cacheSize) {
  7. cache = new LinkedHashMap<T,T>() {
  8. private static final long serialVersionUID = 1L;
  9. @Override
  10. protected boolean removeEldestEntry(Map.Entry<T,T> eldest) {
  11. if (size() > cacheSize) {
  12. return true;
  13. }
  14. return false;
  15. }
  16. };
  17. }
  18. public void add(T key) {
  19. synchronized (cache) {
  20. cache.put(key, null);
  21. }
  22. }
  23. public boolean contains(T key) {
  24. synchronized (cache) {
  25. return cache.containsKey(key);
  26. }
  27. }
  28. }

基于双向链表的 LRU 算法实现

  1. public class LRUCache<K, V> {
  2. class CacheNode {
  3. K key;
  4. V value;
  5. CacheNode prev;
  6. CacheNode next;
  7. }
  8. private final int maxCapacity;
  9. private final Hashtable<K, CacheNode> nodes;
  10. private int curSize;
  11. private CacheNode head;
  12. private CacheNode tail;
  13. public LRUCache(int maxCapacity) {
  14. this.maxCapacity = maxCapacity;
  15. nodes = new Hashtable<>(maxCapacity);
  16. }
  17. /**
  18. * 新增缓存
  19. *
  20. * @param k 缓存key
  21. * @param v 缓存value
  22. */
  23. public void put(K k, V v) {
  24. CacheNode node = nodes.get(k);
  25. if (Objects.isNull(node)) {
  26. if (curSize >= maxCapacity) {
  27. if (Objects.nonNull(tail)) {
  28. nodes.remove(tail.key);
  29. }
  30. removeLast();
  31. }
  32. node = new CacheNode();
  33. }
  34. node.key = k;
  35. node.value = v;
  36. move2Head(node);
  37. curSize++;
  38. }
  39. /**
  40. * 获取缓存
  41. */
  42. public V get(K k) {
  43. if (Objects.isNull(k)) {
  44. return null;
  45. }
  46. final CacheNode node = nodes.get(k);
  47. if (Objects.isNull(node)) {
  48. return null;
  49. }
  50. move2Head(node);
  51. return node.value;
  52. }
  53. /**
  54. * 将缓存删除
  55. *
  56. * @param key 缓存节点 key
  57. */
  58. public V remove(K key) {
  59. if (key == null) {
  60. return null;
  61. }
  62. final CacheNode node = nodes.get(key);
  63. if (node != null) {
  64. if (node.prev != null) {
  65. node.prev.next = node.next;
  66. }
  67. if (node.next != null) {
  68. node.next.prev = node.prev;
  69. }
  70. if (head == node) {
  71. head = node.next;
  72. }
  73. if (tail == node) {
  74. tail = node.prev;
  75. }
  76. }
  77. curSize--;
  78. return node == null ? null : node.value;
  79. }
  80. /**
  81. * 清空容器
  82. */
  83. public void clear() {
  84. nodes.clear();
  85. curSize = 0;
  86. head = null;
  87. tail = null;
  88. }
  89. /**
  90. * 移动到链表头, 表示该节点最新使用过
  91. *
  92. * @param node 节点
  93. */
  94. private void move2Head(CacheNode node) {
  95. if (node == null || node == head) {
  96. return;
  97. }
  98. if (node.prev != null) {
  99. node.prev.next = node.next;
  100. }
  101. if (node.next != null) {
  102. node.next.prev = node.prev;
  103. }
  104. if (head != null) {
  105. node.next = head;
  106. head.prev = node;
  107. }
  108. head = node;
  109. node.prev = null;
  110. if (tail == null) {
  111. tail = head;
  112. }
  113. }
  114. /**
  115. * 删除链表最后一个节点, 表示最近最少使用的缓存
  116. */
  117. private void removeLast() {
  118. if (tail != null) {
  119. if (tail.prev != null) {
  120. tail.prev.next = null;
  121. } else {
  122. head = null;
  123. }
  124. tail = tail.prev;
  125. }
  126. }
  127. }

参考: