缓存有哪些属性

一般缓存会有如下的属性:

  • 命中率:是查询命中缓存的比率
  • 最大元素:缓存中可以存放的最大元素个数,因为缓存不可能无限大
  • 清空策略:当缓存空间不够时候的清空策略

map 实现基本缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.HashMap;
import java.util.Map;

public class SimpleCache {

private Map<String, Object> cache = new HashMap<String, Object>();

private static SimpleCache simpleCache = new SimpleCache();

private SimpleCache() {
}

public static SimpleCache getCache() {
return simpleCache;
}

public void put(String key, Object value) {
cache.put(key, value);
}

public Object get(String key) {
return cache.get(key);
}
}

上面是使用 map 实现了一个最基本的缓存,虽然能工作,但是少了两个缓存应该有的属性,一个是没有最大元素同时也没有清空策略。

还有的问题就是上面的简单缓存实现使用的是 HashMap 对象,这个对象是线程不安全的,还有可能引起 cpu 100% 的问题。如果要解决这个问题,我们可以使用 ConcurrentHashMap 对象。

当然缓存还有的是在 get 的时候,如果当前传入的 key 没有在缓存当中,我们需要从别的地方获取到值,然后存入到缓存当中。

一个无问题的实现:

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
package com.rcx.test.cache;

import java.util.ArrayList;

import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.map.LRUMap;

public class Cache<K, T> {

private long timeToLive;
private LRUMap lruMap;

protected class Entry {
public long lastAccessed = System.currentTimeMillis();
public T value;

protected Entry(T value) {
this.value = value;
}
}

public Cache(long timeToLive, final long timerInterval, int maxItems) {
this.timeToLive = timeToLive * 1000;

lruMap = new LRUMap(maxItems);

if (timeToLive > 0 && timerInterval > 0) {

Thread t = new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(timerInterval * 1000);
} catch (InterruptedException ex) {
}
cleanup();
}
}
});

t.setDaemon(true);
t.start();
}
}

public void put(K key, T value) {
synchronized (lruMap) {
lruMap.put(key, new Entry(value));
}
}

@SuppressWarnings("unchecked")
public T get(K key) {
synchronized (lruMap) {
Entry c = (Entry) lruMap.get(key);

if (c == null)
return null;
else {
c.lastAccessed = System.currentTimeMillis();
return c.value;
}
}
}

public void remove(K key) {
synchronized (lruMap) {
lruMap.remove(key);
}
}

public int size() {
synchronized (lruMap) {
return lruMap.size();
}
}

@SuppressWarnings("unchecked")
public void cleanup() {

long now = System.currentTimeMillis();
ArrayList<K> deleteKey = null;

synchronized (lruMap) {
MapIterator itr = lruMap.mapIterator();

deleteKey = new ArrayList<K>((lruMap.size() / 2) + 1);
K key = null;
Entry c = null;

while (itr.hasNext()) {
key = (K) itr.next();
c = (Entry) itr.getValue();

if (c != null && (now > (timeToLive + c.lastAccessed))) {
deleteKey.add(key);
}
}
}

for (K key : deleteKey) {
synchronized (lruMap) {
lruMap.remove(key);
}
Thread.yield();
}
}
}

—EOF—