Skip to content

Instantly share code, notes, and snippets.

@jingege
Last active January 25, 2022 02:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jingege/6060151 to your computer and use it in GitHub Desktop.
Save jingege/6060151 to your computer and use it in GitHub Desktop.
基于软引用的本地缓存工具
package com.yihaodian.arc.ydc.common.util;
import java.io.Closeable;
import java.io.IOException;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
/**
* hive query cache
* @author jingege
*
* @param <T>
*/
public class HiveResultCache<T> implements Closeable {
private static final Logger logger = Logger
.getLogger(HiveResultCache.class);
private ReferenceQueue<T> reaped = new ReferenceQueue<T>();
private final Map<String, KeyedSoftReference<T>> map = new HashMap<String, KeyedSoftReference<T>>();
private final Map<String, Long> timestamp = new HashMap<String, Long>();
private int lifetime = 1000 * 60 * 60;// 1h
private int cleanInterval = 1000 * 60 * 60 * 2;// 2h
private ScheduledExecutorService executor;
public HiveResultCache() {
startCleaner();
}
public HiveResultCache(int lifetime, int cleanInterval) {
this.lifetime = lifetime*1000;
this.cleanInterval = cleanInterval*1000;
startCleaner();
}
public synchronized void put(String key, T value) {
reap();
map.put(key, new KeyedSoftReference<T>(key, value, reaped));
timestamp.put(key, new Date().getTime());
logger.debug("Put " + key+"+"+value);
}
public synchronized T get(String key) {
reap();
if(!map.containsKey(key)){
return null;
}
T jo = map.get(key).get();
if (jo == null) {
map.remove(key);
timestamp.remove(key);
} else {
if (timestamp.containsKey(key)
&& new Date().getTime() - timestamp.get(key) > lifetime) {
return null;// expired
}
}
logger.debug("Get " + key + ",return " + jo);
return jo;
}
public boolean isCached(String key){
reap();
return this.map.containsKey(key);
}
@SuppressWarnings("unchecked")
private void reap() {
KeyedSoftReference<T> ref;
while ((ref = (KeyedSoftReference<T>) reaped.poll()) != null) {
Object key = ref.getKey();
logger.debug("Reap " + key);
map.remove(key);
timestamp.remove(key);
}
}
private static class KeyedSoftReference<T> extends SoftReference<T> {
private final Object key;
public KeyedSoftReference(Object key, T value, ReferenceQueue<T> q) {
super(value, q);
this.key = key;
}
public Object getKey() {
return key;
}
}
/**
* 定期处理过期的无用的缓存
*/
private void startCleaner() {
executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
synchronized (HiveResultCache.this) {
logger.debug("Cleaning cache,size=" + map.size());
reap();
Iterator<Entry<String, KeyedSoftReference<T>>> it = map
.entrySet().iterator();
long ts = new Date().getTime();
while (it.hasNext()) {
Entry<String, KeyedSoftReference<T>> entry = it.next();
String key = entry.getKey();
KeyedSoftReference<T> ref = entry.getValue();
if (!timestamp.containsKey(key)
|| ts - timestamp.get(key) > lifetime) {
ref.enqueue();// 入队
}
}
reap();
}
}
}, 0/**for debugging**/, cleanInterval, TimeUnit.MILLISECONDS);
}
@Override
public void close() throws IOException {
executor.shutdown();
map.clear();
timestamp.clear();
}
public int getLifetime() {
return lifetime;
}
public void setLifetime(int lifetime) {
this.lifetime = lifetime*1000;
}
public int getCleanInterval() {
return cleanInterval;
}
public void setCleanInterval(int cleanInterval) {
this.cleanInterval = cleanInterval*1000;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment