背景:某个项目需要用到类似redis的功能(存储键值对,并且希望键值对是有过期时间的)。如果只是为了一个小功能,就安装一个redis服务器,那明显太浪费性能。所以开发了这个类,使用MAP来模仿和实现redis的处理。
原理:利用两个Map,一个map用来存储值,一个map用来存储过期时间。另外有一个线程,定期去扫描那些key过期,如果过期,则移除这个值。
注:使用ConcurrentHashMap是为了线程安全。
代码如下:
/**
*
*/
package com.yihu.util.mapRedis;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 使用Map实现redis的功能(只支持单机)
* @author lch 201705
*
*/
public class MapForRedisUtils extends Thread {
private static MapForRedisUtils mapForRedisUtils=null;
private static Map<String,String> map=new ConcurrentHashMap<String,String>();
private static Map<String,Long> expireMap=new ConcurrentHashMap<String,Long>();
/**
* 存储值
* @param key 健
* @param val 值
* @param minute 过期时间(分钟)
*/
public static void setValue(String key,String val,int minute){
try{
map.put(key,val);
expireMap.put(key,System.currentTimeMillis()+minute*60L*1000);
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 获取值
* @param key 健
*/
public static String getValue(String key){
try{
return map.get(key);
}catch(Exception e){
e.printStackTrace();
return null;
}
}
/**
* 获取过期时间(相对于1970-1-1的毫秒数)
* @param key 健
*/
public static long getExpireTime(String key){
try{
return expireMap.get(key);
}catch(Exception e){
e.printStackTrace();
return 0;
}
}
/**
* 设置过期时间(毫秒数)
* @param key 健
* @param expireMills 多少毫秒
*/
public static long setExpireTime(String key,int minute){
try{
return expireMap.put(key,System.currentTimeMillis()+minute*60L*1000);
}catch(Exception e){
e.printStackTrace();
return 0;
}
}
@Override
public void run() {
while(true){
try{
//移除过期的数据
List<String> needRemoveKey=new ArrayList<String>();
for (Map.Entry<String, Long> entry : MapForRedisUtils.expireMap.entrySet()) {
if(entry.getValue()!=null&&entry.getValue()<=System.currentTimeMillis()){
needRemoveKey.add(entry.getKey());
}
}
for(String key:needRemoveKey){
map.remove(key);
expireMap.remove(key);
}
try {
Thread.sleep(10000);//暂停10秒钟,变成死循环
} catch (Exception e1) {
e1.printStackTrace();
}
}catch(Exception e){
try {
Thread.sleep(1000);//防止故障的时候,变成死循环
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
public static void init(){
if(mapForRedisUtils==null){
mapForRedisUtils=new MapForRedisUtils();
mapForRedisUtils.start();//启动监视线程(自动删除过期的数据)
}
}
public static void main(String[] args) throws InterruptedException {
MapForRedisUtils.init();
MapForRedisUtils.setValue("test", "1111111", 1);//设置值
System.out.println(MapForRedisUtils.getValue("test"));//读取值
Thread.sleep(2*60*1000);
System.out.println("2 min after,val="+MapForRedisUtils.getValue("test"));//数据过期之后,再去读取,就发现没有了
}
}