解决map缓存问题

概述

使用java自带的HashMap和ConcurrentHashMap可以做应用程序缓存,但直接使用会导致内存无限增长,产生OOM异常.

解决办法

使用软引用和虚引用

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
import java.lang.ref.SoftReference;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;


* 功能描述: 使用软引用改进Map缓存
*
* @author sunzhiqiang
* @create 2018-08-25
*/
public class <K, V> {

private final ConcurrentHashMap<SoftReference<K>, SoftReference<V>> cache = new ConcurrentHashMap<>();

public V get(K k) {

Objects.requireNonNull(k);

SoftReference<K> key = new SoftReference<>(k);
SoftReference<V> value = cache.get(key);

return value == null ? null : value.get();
}

public V put(K k, V v) {

Objects.requireNonNull(k);
Objects.requireNonNull(v);

SoftReference<K> key = new SoftReference<>(k);
SoftReference<V> value = new SoftReference<>(v);

SoftReference<V> oldValue = cache.put(key, value);

return oldValue == null ? null : oldValue.get();
}

public V remove(K k) {

Objects.requireNonNull(k);

SoftReference<K> key = new SoftReference<>(k);
SoftReference<V> oldValue = cache.remove(key);

return oldValue == null ? null : oldValue.get();
}
}

使用LRUMap

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
import java.util.LinkedHashMap;
import java.util.Map;


* 功能描述: 最近最少使用Map
*
* @author sunzhiqiang
* @create 2018-08-25
*/
public class LRUMap<K, V> extends LinkedHashMap<K, V> {

private final int max;

public LRUMap(int max) {
super((int) (max * 1.4f), 0.75f, true);
this.max = max;
}


protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > max;
}

public synchronized V getValue(K k) {
return get(k);
}

public synchronized V putValue(K k, V v) {
return put(k, v);
}

public synchronized boolean removeValue(K k, V v) {
return remove(k, v);
}
}

使用guava cache

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
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;


* 功能描述: 使用guava cache
*
* @author sunzhiqiang
* @create 2018-08-25
*/
public class GuavaCacheMap<K, V> {

private LoadingCache<K, V> cache = null;

public GuavaCacheMap() {
cacheInit();
}

private void cacheInit() {

cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(30L, TimeUnit.SECONDS)
.expireAfterAccess(30L, TimeUnit.SECONDS)
.refreshAfterWrite(20L, TimeUnit.SECONDS)
.weakKeys()
.build(new CacheLoader<K, V>() {

public V load(K k) throws Exception {
return null;
}
});
}

public V get(K k) throws ExecutionException {

return cache.get(k);
}

public void put(K k, V v) {

cache.put(k, v);
}
}