引言

实现了一个简单的内存缓存:

  1. 元素个数有限
  2. 能自动移除最老的条目
  3. 通过插入顺序遍历它
  4. 是线程安全的集合
  5. 适用于读多写少的场景

基于组合优于继承的思想,封装了​​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;
}
}