直接上代码
缓存对象
import org.apache.log4j.Logger;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 基于软引用实现的缓存,当内存不够使会自动释放缓存内容,以避免OOM
* User: yfzhangbin
* Date: 13-8-16
* Time: 下午4:02
*/
public class SoftReferenceCache<K, V> {
private static final Logger log = Logger.getLogger(SoftReferenceCache.class);
private Map<K, InnerSoftReference<V>> cache; // 缓存对象池,<K, R->V>
private ReferenceQueue<V> queue; // 引用队列,当GC执行后被回收的缓存对象的软引用将被入队,以方便从缓存池中清除失效的软引用。
private ReadWriteLock lock; // 读写锁
public SoftReferenceCache() {
cache = new HashMap<K, InnerSoftReference<V>>();
queue = new ReferenceQueue<V>();
lock = new ReentrantReadWriteLock(false);
}
/**
* 向缓存池中添加对象
* @param key
* @param value
*/
public void put(K key, V value) {
try {
lock.writeLock().lock();
clearInvalidReference();
cache.put(key, new InnerSoftReference<V>(key, value, queue));
} finally {
lock.writeLock().unlock();
}
}
/**
* 从缓存池中获取对象
* @param key
* @return
*/
public V get(K key) {
try {
lock.readLock().lock();
InnerSoftReference<V> softReference = cache.get(key);
V v = null;
if (softReference != null)
v = softReference.get();
return v;
} finally {
lock.readLock().unlock();
}
}
/**
* 从缓存池中清除失效的软引用
* 备注:失效软引用是指向null的引用
*/
private void clearInvalidReference() {
InnerSoftReference<V> softReference;
while ((softReference = (InnerSoftReference)queue.poll()) != null) {
if (softReference.get() == null)
cache.remove(softReference.getKey());
}
}
/**
* 缓存池中对象的个数
* @return
*/
public int size() {
try {
lock.readLock().lock();
int size = cache.size();
log.info(Thread.currentThread().getName() + " 缓存池中对象的个数: " + size);
return size;
} finally {
lock.readLock().unlock();
}
}
/**
* 清空缓存池,定时worker每次计算前调用此方法可清除历史记录
*/
public void clearCache() {
try {
lock.writeLock().lock();
cache = new HashMap<K, InnerSoftReference<V>>();
queue = new ReferenceQueue<V>();
log.info(Thread.currentThread().getName() + "清空缓存池!");
} finally {
lock.writeLock().unlock();
}
}
/**
* 封装了软引用,便于获取对应缓存池中的key
* @param <V>
*/
private class InnerSoftReference<V> extends SoftReference<V> {
private K key;
private InnerSoftReference(K key, V value, ReferenceQueue<V> queue) {
super(value, queue);
this.key = key;
}
public K getKey() {
return key;
}
}
}
测试类
import com.jd.recommend.service.util.*;
import org.apache.log4j.Logger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 测试类
* User: yfzhangbin
* Date: 13-8-16
* Time: 下午5:18
*/
public class TestSoftReferenceCache {
private static final Logger log = Logger.getLogger(TestSoftReferenceCache.class);
private static int MAX_COUNT = 100000;
private static String KEY_PREFIX = "KEY_";
private static SoftReferenceCache<String, byte[]> cache = new SoftReferenceCache<String, byte[]>();
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
es.submit(new Customer());
es.submit(new Customer());
es.submit(new Customer());
es.submit(new Customer());
es.submit(new Customer());
es.shutdown();
}
static class Customer implements Runnable {
@Override
public void run() {
while (true) {
for (int i = 0; i < MAX_COUNT; i ++) {
byte[] a = cache.get(KEY_PREFIX + i);
if (a == null) {
a = new byte[1024];
cache.put(KEY_PREFIX + i, a);
log.info(Thread.currentThread().getName() + " 向缓存池中添加对象[" + (KEY_PREFIX + i) + "]: " + a);
} else {
log.info(Thread.currentThread().getName() + " 从缓存池中获取对象[" + (KEY_PREFIX + i) + "]: " + a);
}
}
}
}
}
}