Java带有效期的Map做缓存

项目中做了一个基于websocket的消息推送功能,客户端浏览器可以实时获取到通知消息,将这些未读消息放在缓存中,方便客户端浏览器随时读取,但项目规模不大,不至于用MQ、Redis等服务器。

那怎么保存这些通知消息呢?

Map可以存放用户和对应的消息,但是没办法对过期消息进行维护,于是自己写了一个缓存类,重写了Map的几个主要方法。

package com.util.cache;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 带过期时间的map
 * @param 
 * @param 
 */
public class CacheMap extends ConcurrentHashMap {
	
	private static final long serialVersionUID = 3666697890499256321L;

	/**
	 * 保存key和对应的过期时间
	 */
	private Map expireMap = new HashMap();
	
	/**
	 * 默认过期时间
	 */
	private long EXPIRE_TIME = 1000;
	
	public CacheMap(){
		super();
	}
	
	public CacheMap(long expire){
		this.EXPIRE_TIME = expire;
	}
	
	public CacheMap(TimeUnit unit,long duration){
		this.EXPIRE_TIME = unit.toMillis(duration);
	}
	
	@Override
	public V put(K key, V value) {
		if(key == null){
			return null;
		}
		expireMap.put(key, System.currentTimeMillis() + EXPIRE_TIME);
		return super.put(key, value);
	}
	
	public V put(K key, V value,long expireTime) {
		if(key == null){
			return null;
		}
		expireMap.put(key, System.currentTimeMillis() + expireTime);
		return super.put(key, value);
	}
	
	@Override
	public V get(Object key) {
		if(key == null){
			return null;
		}
		return super.get(key);
	}
	
	@Override
	public V remove(Object key) {
		if(key == null){
			return null;
		}
		expireMap.remove(key);
		return super.remove(key);
	}
	
	/**
	 * 是否过期
	 * @param key
	 * @return
	 */
	public boolean isExpired(K key){
		if(key == null || !containsKey(key)){
			return false;
		}else {
			long time1 = expireMap.get(key);
			long time2 = System.currentTimeMillis();
			return (time2 - time1) > 0;
		}
	}
	
	/**
	 * 移除所有过期键值对
	 * @return
	 */
	public void removeALLExpired(){
		for(K key : this.keySet()){
		   if(isExpired(key)){
			   remove(key);
		   }
		}
	}
	
}

如何对缓存持久化?

CacheManager类,单例模式管理缓存对象。ObjectOutputStream流直接写入文件。项目启动的时候,ObjectInputStream流读取文件。

package com.util.cache;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 缓存管理
 *
 */
public class CacheManager {

	private static CacheMap cache = new CacheMap(TimeUnit.DAYS,10);
	
	private static String CACHE_FILE_PATH = "D:\\noticeCache.db";
	
	public static CacheMap getCache(){
		return cache;
	}
	
	/**
	 * 持久化缓存对象到磁盘文件
	 */
	public static void cachePersist(){
		File file = new File(CACHE_FILE_PATH);
		FileOutputStream fos = null;
		ObjectOutputStream oos = null;
		try {
			fos = new FileOutputStream(file);
			oos = new ObjectOutputStream(fos);
			oos.writeObject(cache);
			System.out.println("缓存持久化----");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			try {
				if(fos != null){
					fos.close();
				}
				if(oos != null){
					oos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 从磁盘文件读取缓存对象
	 */
	public static void loadCache(){
		File file = new File(CACHE_FILE_PATH);
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		if(!file.exists()){
			return;
		}
		try {
			fis = new FileInputStream(file);
			ois = new ObjectInputStream(fis);
			try {
				cache = (CacheMap)ois.readObject();
				System.out.println("缓存加载----");
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			try {
				if(fis != null){
					fis.close();
				}
				if(ois != null){
					ois.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

如何定期清理过期数据呢?

1、可以使用Java原生的ScheduledExecutorService

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(new Runnable() {
	@Override
	public void run() {
		cache.removeALLExpired();
		System.out.println("缓存清理----");
		cachePersist();
	}
}, 10, 10, TimeUnit.SECONDS);

2、使用Spring Quartz

 

你可能感兴趣的:(Java带有效期的Map做缓存)