引言
实现了一个简单的内存缓存:
- 元素个数有限
- 能自动移除最老的条目
- 通过插入顺序遍历它
- 是线程安全的集合
- 适用于读多写少的场景
基于组合优于继承的思想,封装了LinkedHashMap
,并且只有在写操作的时候才进行加锁。
代码
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
/**
* 遍历顺序(values()方法)是插入顺序的缓存,并且具有CopyOnWrite性质
* @param <K>
* @param <V>
*/
public class CopyOnWriteCache<K, V> {
private LinkedHashMap<K, V> core;
private static final int MAX_ENTRIES = 10000;
private final int maxSize;
private volatile Map<K, V> view;
private final transient ReentrantLock lock = new ReentrantLock();
public CopyOnWriteCache() {
this(MAX_ENTRIES);
}
public CopyOnWriteCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException();
}
this.maxSize = maxSize;
core = new LinkedHashMap<K, V>(maxSize) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > maxSize; //当超过最大条目数时,移除最老的
}
};
}
private CopyOnWriteCache(CopyOnWriteCache<K, V> that) {
this.core = that.core;
this.maxSize = that.maxSize;
}
public void put(K key, V val) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//拷贝一份老的
LinkedHashMap<K, V> newCore = new LinkedHashMap<K, V>(this.core) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > maxSize;
}
};
newCore.put(key, val);
this.core = newCore;
view = null;
} finally {
lock.unlock();
}
}
public V get(K key) {
return core.get(key);
}
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
this.core = new LinkedHashMap<K, V>(this.core) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > maxSize;
}
};
view = null;
} finally {
lock.unlock();
}
}
public int size() {
return core.size();
}
public Collection<V> values() {
return getView().values();
}
public Set<Map.Entry<K, V>> entrySet() {
return getView().entrySet();
}
public V remove(K key) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
LinkedHashMap<K, V> newCore = new LinkedHashMap<K, V>(this.core) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > maxSize;
}
};
view = null;
V v = newCore.remove(key);
this.core = newCore;
return v;
} finally {
lock.unlock();
}
}
@Override
public String toString() {
return core.toString();
}
private Map<K, V> getView() {
Map<K, V> result = view;
if (result == null) {
result = Collections.unmodifiableMap(core);
view = result;
}
return result;
}
}