Debian GNU/Linux Sarge で java memcached client を試す ということをやってみて、ファイルやDBはまだしも、メモリなら簡単だろうな、ということで叩き台を作ってみた。
import java.util.*;
/**
* オブジェクトをメモリにキャッシュします。
*/
public final class MemoryCache {
// test
public static void main(String[] args){
{
MemoryCache mc = new MemoryCache(3);
for(int i=0; i<10; i++){
mc.set("" + i, "Data" + i, new Date().getTime() + (30 * i));
try{Thread.sleep(100);}catch(Exception e){}
Object data = mc.get("" + i);
System.out.println(data);
}
for(int i=0; i<10; i++){
Object data = mc.get("" + i);
System.out.println(data);
}
}
{
MemoryCache mc = new MemoryCache(3);
mc.debug = true;
for(int i=0; i<10; i++){
mc.set("" + i, "Data" + i, new Date().getTime() + (30 * i));
try{Thread.sleep(100);}catch(Exception e){}
Object data = mc.get("" + i);
System.out.println(data);
}
for(int i=0; i<10; i++){
Object data = mc.get("" + i);
System.out.println(data);
}
}
}
private static final String FQCN = MemoryCache.class.getName();
private final Map cdmap;
public boolean debug;
/**
* @param capacity キャッシュ内に保存するオブジェクトの最大数(厳密ではない)
*/
public MemoryCache(int capacity){
// cdmap = Collections.synchronizedMap(new CacheRepository(this, capacity));
cdmap = new CacheRepository(this, capacity);
}
private static class CacheRepository extends LinkedHashMap {
private final MemoryCache cm;
private final int capacity;
private CacheRepository(MemoryCache cm, int capacity){
super(capacity+1, 0.75f, true); // 順序モード=true(アクセス順)
this.cm = cm;
this.capacity = capacity;
}
protected boolean removeEldestEntry(Map.Entry eldest){
boolean result = size() > capacity; // 削除する場合はtrueを返す
if(result){
// ここで削除されるオブジェクトをファイルやDBに保存できると良いなぁ
cm.debug(FQCN + ": remove eldest cache data (" + ((CachedData)eldest.getValue()).value + ")"); // DEBUG
}
return result;
}
}
private static class CachedData{
public Object value;
public long expiry;
}
/**
* オブジェクトをキャッシュに入れます。
* @param expiry オブジェクトの有効期限(Epoch Time からのミリ秒数), 有効期限なしの場合は負の値を指定
*/
public synchronized void set(String key, Object value, long expiry){
CachedData cd = new CachedData();
cd.value = value;
if(expiry < 0){
expiry = Long.MAX_VALUE; // long の最大値を入れておけばラク
}
cd.expiry = expiry;
cdmap.put(key, cd);
}
/**
* オブジェクトをキャッシュから取り出します。
* @param expiry オブジェクトの有効期限(Epoch Time からのミリ秒数), 有効期限なしの場合は負の値を指定
*/
public synchronized Object get(String key){
Object obj = cdmap.get(key);
if(obj != null){
CachedData cd = (CachedData)obj;
if(new Date().getTime() > cd.expiry){
// オブジェクトの有効期限切れ
if(debug){
debug(FQCN + ": remove expired cache data (" + cd.value + ")"); // DEBUG
}
cdmap.remove(key);
return null;
}else{
return cd.value;
}
}else{
return null;
}
}
void debug(Object x){
if(debug){
System.out.println(x);
}
}
}
当然、このつくりでは JVM 起動中しかメモリにキャッシュされない。
tags: zlashdot Java Java
Posted by NI-Lab. (@nilab)