一,基本的原理
偶遇storm中的rotatecache算法,特地研究一下。
核心:
1,是採用了鏈表來組織多個桶來存儲數據;
2,插入數據時直接插入到第一個桶中,清除到其它桶中的同key值的數據;
3,刪除數據移除所有桶中的數據(此處需要遍歷)
4,回收數據的時候,採用了非常巧妙的方式,在鏈表頭新加一個桶,刪除尾部的桶刪除掉,如果帶回調,調用一下回調函數。
二,代碼
1,涉及到三個文件,rotatingmap本身代碼
/*************************************************************************
> File Name: rotatingmap.java
> Author:zhangtx
> Mail: [email protected]
> Created Time: 2016年4月12日 星期四 13時12分14秒
************************************************************************/
package org.jinher.research.RotatingMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
public class RotatingMap<K,V> {
private static final int DEFAULT_NUM_BUCKETS=3;
/*
* rotate的回調接口口
* */
public static interface ExpiredCallback<K,V>{
public void expire(K key,V val);
}
private LinkedList<HashMap<K,V>> _buckets;
private ExpiredCallback _callback;
public RotatingMap(int numBuckets,ExpiredCallback<K,V> callback)
{
if (numBuckets<2)
{
throw new IllegalArgumentException("numBuckets must be >=2");
}
_buckets=new LinkedList<HashMap<K,V>>();
for(int i=0;i<numBuckets;i++)
{
_buckets.add(new HashMap<K,V>());
}
_callback=callback;
}
public RotatingMap(ExpiredCallback<K,V> callback)
{
this(DEFAULT_NUM_BUCKETS,callback);
}
public RotatingMap(int numBuckets)
{
this(numBuckets,null);
}
public Map<K,V> rotate()
{
Map<K,V> dead=_buckets.removeLast();
_buckets.addFirst(new HashMap<K,V>());
if(_callback!=null)
{
for(Entry<K,V> entry:dead.entrySet())
{
_callback.expire(entry.getKey(),entry.getValue());
}
}
return dead;
}
public boolean containsKey(K key)
{
for(HashMap<K,V> bucket:_buckets)
{
if (bucket.containsKey(key))
{
return true;
}
}
return false;
}
public V get(K key)
{
for(HashMap<K,V> bucket:_buckets)
{
if(bucket.containsKey(key))
{
return bucket.get(key);
}
}
return null;
}
/*存儲數據*/
public void put(K key,V value)
{
Iterator<HashMap<K,V>> it=_buckets.iterator();
/*put to the first bucket*/
HashMap<K,V> bucket=it.next();
bucket.put(key, value);
/*remove key from others bucket*/
while(it.hasNext())
{
bucket=it.next();
bucket.remove(key);
}
}
public Object remove(K key)
{
/*移除數據*/
for(HashMap<K,V> bucket:_buckets)
{
if(bucket.containsKey(key))
{
return bucket.remove(key);
}
}
return null;
}
public int size()
{
int size=0;
/*計算各個桶中數據的個數之和*/
for(HashMap<K,V> bucket:_buckets)
{
size+=bucket.size();
}
return size;
}
}
2,回調接口實現代碼
/*************************************************************************
> File Name: rotatingmap.java
> Author:zhangtx
> Mail: [email protected]
> Created Time: 2016年4月12日 星期四 13時12分14秒
************************************************************************/
package org.jinher.research.RotatingMap;
public class EventHandler<K,V> implements RotatingMap.ExpiredCallback<K, V> {
public void expire(K key, V val) {
// TODO Auto-generated method stub
System.out.println("key="+key+",val="+val);
}
}
3,測試代碼
/*************************************************************************
> File Name: rotatingmap.java
> Author:zhangtx
> Mail: [email protected]
> Created Time: 2016年4月12日 星期四 13時12分14秒
************************************************************************/
package org.jinher.research.RotatingMap;
import java.text.SimpleDateFormat;
import java.util.Date;
public class RotatingMapStarter
{
RotatingMap<String,String> m_rotatingMap=null;
RotatingMap.ExpiredCallback<String, String> m_eventHandler=null;
long m_lastRotate=System.currentTimeMillis();
long m_rotateTime;
public RotatingMapStarter(int n,int rotateTime)
{
m_eventHandler=new EventHandler<String,String>();
m_rotatingMap=new RotatingMap<String,String>(4,m_eventHandler);
m_lastRotate=System.currentTimeMillis();
m_rotateTime=1000L*rotateTime;
}
public RotatingMap<String,String> getRotatingMap()
{
return m_rotatingMap;
}
public void setRotatingMap(RotatingMap<String,String> rotatingMap)
{
this.m_rotatingMap=rotatingMap;
}
public void startConnMonitor()
{
Thread thread=new Thread("Server Monitor")
{
public void run()
{
while(true)
{
runcore();
}
}
public void runcore()
{
try
{
Thread.currentThread().sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
long now=System.currentTimeMillis();
if(now-m_lastRotate>m_rotateTime)
{
m_rotatingMap.rotate();
m_lastRotate=now;
}
else
{
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(new Date(now)));
}
}
};
thread.start();
}
public static void main(String[] args)
{
RotatingMapStarter rotatingMapStarter = new RotatingMapStarter(4, 10);
rotatingMapStarter.startConnMonitor();
String value = "zhang";
String key = "1";
rotatingMapStarter.getRotatingMap().put(key, value);
System.out.println("key="+key+",value="+rotatingMapStarter.getRotatingMap().get(key));
String value1 = "tianxiang";
String key1 = "2";
rotatingMapStarter.getRotatingMap().put(key1, value1);
System.out.println("key="+key1+",value="+rotatingMapStarter.getRotatingMap().get(key1));
try {
Thread.currentThread().sleep(100000000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
三,結果
key=1,value=zhang
key=2,value=tianxiang
2016-04-12 14:48:48
2016-04-12 14:48:50
2016-04-12 14:48:51
2016-04-12 14:48:52
2016-04-12 14:48:54
2016-04-12 14:48:57
2016-04-12 14:48:58
2016-04-12 14:48:59
2016-04-12 14:49:00
2016-04-12 14:49:02
2016-04-12 14:49:03
2016-04-12 14:49:04
2016-04-12 14:49:07
2016-04-12 14:49:08
2016-04-12 14:49:10
2016-04-12 14:49:11
2016-04-12 14:49:12
2016-04-12 14:49:22
2016-04-12 14:49:23
2016-04-12 14:49:24
2016-04-12 14:49:25
2016-04-12 14:49:26
key=2,val=tianxiang
key=1,val=zhang
2016-04-12 14:49:33
2016-04-12 14:49:34
2016-04-12 14:49:35