基于LinkHashMap的LRU缓存淘汰

LRU缓存淘汰

LRU缓存淘汰是redis中的一种淘汰策略, 当内存大小不足以存放数据时, 此时存入新数据, 将删除较早存入的数据.
在dubbo中使用LRU来缓存 hostName.
在mysql中使用LRU来缓存 serverSideStatementCheckCache 和 serverSideStatementCache.

代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package com.ipaynow.tool.lru;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* 基于LinkedHashMap LRU 缓存淘汰, 以下框架中都有使用
* dubbo com.alibaba.dubbo.common.utils.LRUCache
* com.mysql.jdbc.util.LRUCache
*
* @author liuzhihang
* @date 2018/11/20 10:43
*/
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {

/**
* 设置最大容量
*/
private volatile int maxCapacity;

private static final int DEFAULT_MAX_CAPACITY = 1000;

private static final float DEFAULT_LOAD_FACTOR = 0.75f;

private final Lock lock = new ReentrantLock();

public LRULinkedHashMap() {
this.maxCapacity = DEFAULT_MAX_CAPACITY;
}

public LRULinkedHashMap(int maxCapacity) {
// accessOrder设置为true 按照时间排序
super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
this.maxCapacity = maxCapacity;
}

/**
* 当链表长度大于最大容量时 删除最旧的元素
*/
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxCapacity;
}

@Override
public boolean containsKey(Object key) {
try {
lock.lock();
return super.containsKey(key);
} finally {
lock.unlock();
}
}

@Override
public V get(Object key) {
try {
lock.lock();
return super.get(key);
} finally {
lock.unlock();
}
}

@Override
public V put(K key, V value) {
try {
lock.lock();
return super.put(key, value);
} finally {
lock.unlock();
}
}

@Override
public V remove(Object key) {
try {
lock.lock();
return super.remove(key);
} finally {
lock.unlock();
}
}

@Override
public int size() {
try {
lock.lock();
return super.size();
} finally {
lock.unlock();
}
}

@Override
public void clear() {
try {
lock.lock();
super.clear();
} finally {
lock.unlock();
}
}

public int getMaxCapacity() {
return maxCapacity;
}

public void setMaxCapacity(int maxCapacity) {
this.maxCapacity = maxCapacity;
}

}

测试代码及结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.ipaynow.tool.lru;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import java.util.Map;

/**
* @author liuzhihang
* @date 2018/11/20 10:58
*/
public class LRUTest {

public static void main(String[] args) throws InterruptedException {

LRULinkedHashMap<String, String> map = new LRULinkedHashMap<>(5);

for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
map.put(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS")), "value" + i);
}


for (Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<String, String> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "------------" + value);
}
}

}

控制台输出结果:

1
2
3
4
5
6
7
2018-11-20 11:13:21 398------------value5
2018-11-20 11:13:22 399------------value6
2018-11-20 11:13:23 400------------value7
2018-11-20 11:13:24 400------------value8
2018-11-20 11:13:25 400------------value9

Process finished with exit code 0