定时删除Map中的元素 -- Map中的元素自动过期

不会写博客,就简介绍一下吧。主要功能是定时删除Map中的元素,
类似于redis中的get和set,是增强型HashMap,
在put时可为每个KEY增加一个过期时间,
如果没有为KEY设置过期时间,那么这个key是永久的。

之前盲写的没有经过测试,实在是对不起大家,
这次修复了@xiyang9520提出的BUG,还增加了测试代码,感谢@xiyang9520



import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
 
/**
 * Map's KEY is automatic expire
 * @author zhangshuai
 */
@SuppressWarnings("unchecked")
public class TimerExpireHashMap<K, V> extends HashMap<K, V> {
 
	private static final long serialVersionUID = -609074433772310225L;

	// 定时删除过期键,间隔时间
    private static final long CHECK_TIME_SECOND = 1 * 1000;
 
    // 默认过期时间容器初始化数量
    private static final int DEFAULT_INITIAL_CAPACITY = 8;
 
    // 定时器
    private Timer timer = new Timer();
 
    // 期时间容器
    private Map<Object, Long> timerMap;
 
    // 过期数据回调
    @SuppressWarnings("rawtypes")
	private TimerExpireHashMapCallback timerExpireHashMapCallback ;
 
    /**
     * 定时删除过期键
     */
    private TimerTask timerTask = new TimerTask() {
		@SuppressWarnings("unchecked")
		@Override
        public void run() {
            long currentTime = System.currentTimeMillis();
            timerMap.keySet().removeIf(key -> {
            	Long keyTime = timerMap.get(key);
                if (currentTime >= keyTime.longValue()) {
                    if(timerExpireHashMapCallback != null) {
                        try {
                            timerExpireHashMapCallback.callback((K)key, (V)TimerExpireHashMap.super.get(key));
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                        }
                    }
                    remove(key);
                    return true;
                }
                return false;
            });
        }
    };
 
    /**
     * 构造方法
     * @param initialCapacity   容器初始数量
     * @param loadFactor        随机因子
     */
    public TimerExpireHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        init(initialCapacity, loadFactor);
    }
 
    /**
     * 构造方法
     * @param initialCapacity   容器初始数量
     */
    public TimerExpireHashMap(int initialCapacity) {
        super(initialCapacity);
        init(initialCapacity, 10);
    }
 
    /**
     * 构造方法
     */
    public TimerExpireHashMap() {
        super();
        init(DEFAULT_INITIAL_CAPACITY, 	10);
    }
 
    /**
     * 构造方法
     * @param map
     */
    public TimerExpireHashMap(Map<K, V> map) {
        super(map);
        init(DEFAULT_INITIAL_CAPACITY, 10);
    }
 
    /**
     * 初始化过期时间容器
     * @param initialCapacity   容器初始数量
     * @param loadFactor        随机因子
     */
    private void init(int initialCapacity, float loadFactor) {
        timerMap = new HashMap<>(initialCapacity, loadFactor);
        timer.scheduleAtFixedRate(timerTask, 0, CHECK_TIME_SECOND);
    }
 
    /**
     * 获取数据
     * @param key
     */
    @Override
    public V get(Object key) {
        Long expireTime = checkKeyExpireTime(key);
        if (expireTime == null || expireTime > 0) {
            return super.get(key);
        }
        return null;
    }
 
    /**
     * 放入数据
     * @param key           键值
     * @param value         数据
     * @param expireSecond  过期时间(秒)
     * @return  数据
     */
    public V put(K key, V value, Long expireSecond) {
        if(expireSecond != null && expireSecond.longValue() > 0) {
            setKeyExpireTime(key, expireSecond);
        }
        return super.put(key, value);
    }
 
    /**
     * 返回key过期剩余时间(秒)
     * @param key   键值
     * @return      返回key过期剩余时间(秒)
     */
    public Long checkKeyExpireTime(Object key) {
        Long second = timerMap.get(key);
        if(second == null) {
            return null;
        }
        long currentTime = System.currentTimeMillis();
        return ((second.longValue() - currentTime) / 1000);
    }
 
    /**
     * 为键值设置过期时间
     * @param key               键值
     * @param expireSecond      过期时间(秒)
     */
    public void setKeyExpireTime(Object key, Long expireSecond) {
		if (expireSecond != null && expireSecond.longValue() > 0 /* && this.containsKey(key) */) {
            long currentTime = System.currentTimeMillis();
            long expireTime = currentTime + (expireSecond * 1000);
            timerMap.put(key, expireTime);
        }
    }
 
    /**
     * 设置过期数据设置监听
     * @param timerExpireHashMapCallback    监听回调
     */
    public void setTimerExpireHashMapCallback(TimerExpireHashMapCallback<K, V> timerExpireHashMapCallback) {
        this.timerExpireHashMapCallback = timerExpireHashMapCallback;
    }
 
    /**
     * 数据设置回调
     * @param <K>
     * @param <V>
     */
    static interface TimerExpireHashMapCallback<K, V> {
        /**
         * 监听回调
         * @param key   过期键
         * @param value 过期值
         * @throws RuntimeException
         */
        public void callback(K key, V value) throws RuntimeException;
    }
}




以下是测试代码
/**
 * The test Map's KEY is automatic expire
 *
 * @author zhangshuai
 * @date 2021年05月17日 11时03分38秒
 * @version V1.0
 *
 */
public class Test {

	private static final TimerExpireHashMap<String, String> cacheMap = new TimerExpireHashMap<>();
	
	public static void main(String[] args) {
		System.out.println("------- test start --------");
		new Test().testExpire();
		System.out.println("------- test end --------");
	}
	
	private void testExpire() {
		cacheMap.put("a", "1", 1L);
		cacheMap.put("b", "2", 2L);
		cacheMap.put("c", "3", 3L);
		cacheMap.put("d", "4", 4L);
		cacheMap.put("e", "5", 5L);
		
		cacheMap.setTimerExpireHashMapCallback((k, v) -> System.out.println(MessageFormat.format("Key {0} has expire!!", k)));
	}
}
  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
下面是一个使用 `Map` 实现简单本地缓存,并且每天早上定时任务清除并重新存储数据的示例代码: ```java import java.util.HashMap; import java.util.Map; import java.util.Timer; import java.util.TimerTask; public class LocalCacheExample { private static Map<String, Object> cache = new HashMap<>(); public static void main(String[] args) { // 模拟每天早上定时任务时间 long interval = 24 * 60 * 60 * 1000; // 24小时 // 执行定时任务 Timer timer = new Timer(); timer.schedule(new CacheRefreshTask(), interval, interval); // 存储数据到缓存 storeData("key1", "value1"); storeData("key2", "value2"); // 从缓存获取数据 System.out.println(getData("key1")); // 输出: value1 System.out.println(getData("key2")); // 输出: value2 // 等待定时任务执行完毕 try { Thread.sleep(interval); } catch (InterruptedException e) { e.printStackTrace(); } // 重新从缓存获取数据 System.out.println(getData("key1")); // 输出: null System.out.println(getData("key2")); // 输出: null // 停止定时任务 timer.cancel(); } private static void storeData(String key, Object value) { cache.put(key, value); } private static Object getData(String key) { return cache.get(key); } private static class CacheRefreshTask extends TimerTask { @Override public void run() { // 清除缓存 cache.clear(); // 重新存储数据到缓存 storeData("key1", "new value1"); storeData("key2", "new value2"); System.out.println("缓存已更新"); } } } ``` 在上面的示例,使用 `HashMap` 实现了一个简单的本地缓存 `cache`。定时任务 `CacheRefreshTask` 负责在每天早上清除并重新存储数据。首先,通过 `storeData()` 方法将数据存储到缓存,然后通过 `getData()` 方法从缓存获取数据。等待定时任务执行完毕后,再次从缓存获取数据,可以看到数据已被清除并重新存储。 请注意,上面的示例只是一个简单的示例,实际应用可能需要考虑并发访问、缓存过期策略等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值