首页 > 编程知识 正文

java实现本地缓存的用例,java 实现缓存

时间:2023-05-06 04:33:33 阅读:277395 作者:801

java实现本地缓存 缓存

缓存,将程序或系统中重复用到的数据缓存在内存中,加快访问速度,减少系统开销,提高系统效率的方案。

数据存储方式主要分2种:

文件 数据保存在文件中,做持久化。内存 数据保存在内存中,也就是创建一个静态内存区域,本文中数据保存在静态区域,使用MAP保存keyvalue数据。 开源缓存框架 Redis
Redis是基于内存、可持久化的日志型、Key-Value数据库高性能存储系统,并提供多种语言的API.memcached
是一个自由开源的,高性能,分布式内存对象缓存系统。基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)。 解决场景

目前在开发的项目中,不希望引入太多外部服务,引入分布式缓存框架例如Redis,还需要部署与维护,这会大大增加对项目的维护成本。

Java实现本地缓存框架逻辑 框架基本定义 数据存储格式 key-value,仅针对字符串缓存。数据有效性,增加超时时间失效逻辑失效策略:定期删除与懒惰淘汰并行

定期删除策略

定期删除策略是每隔一段时间检测已过期的缓存,并且降之删除。这个策略的优点是能够确保过期的缓存都会被删除。同时也存在着缺点,过期的缓存不一定能够及时的被删除,这跟我们设置的定时频率有关系,另一个缺点是如果缓存数据较多时,每次检测也会给 cup 带来不小的压力。

懒惰淘汰策略

懒惰淘汰策略是在使用缓存时,先判断缓存是否过期,如果过期将它删除,并且返回空。这个策略的优点是只有在查找的时候,才判断是否过期,对 CUP 影响较小。同时这种策略有致命的缺点,当存入了大量的缓存,这些缓存都没有被使用并且已过期,都将成为无效缓存,这些无效的缓存将占用你大量的内存空间,最后导致服务器内存溢出。
我们简单的了解了一下 Redis 的两种过期缓存处理策略,每种策略都存在自己的优缺点。所以我们在使用过程中,可以将两种策略组合起来,结合效果还是非常理想的。

逻辑顺序 定义缓存map, 定义定时移除时效数据的任务,在static代码块中初始化。定义缓存对象,包含值和过期时间。定义定时移除时效数据的异步任务。实现俩种时效策略移除数据的逻辑 remove + removeAll.实现put与get方法。 框架中用到的定时任务模块

private final static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(new Task(), INITIAL_DELAY_TIME, PERIOD_TIME, TimeUnit.SECONDS);

初始化线程池,启动定时执行任务scheduleAtFixedRate

new Task() 定时任务执行的具体业务逻辑INITIAL_DELAY_TIME 启动后延迟时间执行(秒)PERIOD_TIME 每次执行间隔(秒) 执行结果

定时任务策略:延迟5秒执行,每隔5秒执行一次 (实际失效策略时间可以放长一点)

首先添加缓存数据

LocalCache.put("a", "10a", 7);LocalCache.put("b", "10b", 12);LocalCache.put("c", "10c", 30);2019-12-25 21:00:19,914 [http-nio-9060-exec-1] INFO LocalCache 62 - 添加缓存,key=a, value=10a, expire=7秒2019-12-25 21:00:19,915 [http-nio-9060-exec-1] INFO LocalCache 62 - 添加缓存,key=b, value=10b, expire=12秒2019-12-25 21:00:19,915 [http-nio-9060-exec-1] INFO LocalCache 62 - 添加缓存,key=c, value=10c, expire=30秒

定时任务执行第二次 10s后,移除缓存数据a

2019-12-25 21:00:24,919 [pool-3-thread-1] INFO LocalCache 89 - 定期删除策略: 开始执行, store={a=LocalCache.Cache(value=10a, expire=1577278826915), b=LocalCache.Cache(value=10b, expire=1577278831915), c=LocalCache.Cache(value=10c, expire=1577278849915)}2019-12-25 21:00:29,918 [pool-3-thread-1] INFO LocalCache 89 - 定期删除策略: 开始执行, store={a=LocalCache.Cache(value=10a, expire=1577278826915), b=LocalCache.Cache(value=10b, expire=1577278831915), c=LocalCache.Cache(value=10c, expire=1577278849915)}2019-12-25 21:00:29,919 [pool-3-thread-1] INFO LocalCache 94 - 定期删除策略: 移除超时失效数据, key=a, value=10a, time=1577278826915

定时任务执行第三次 15s后,移除缓存数据b

2019-12-25 21:00:34,918 [pool-3-thread-1] INFO LocalCache 89 - 定期删除策略: 开始执行, store={b=LocalCache.Cache(value=10b, expire=1577278831915), c=LocalCache.Cache(value=10c, expire=1577278849915)}2019-12-25 21:00:34,919 [pool-3-thread-1] INFO LocalCache 94 - 定期删除策略: 移除超时失效数据, key=b, value=10b, time=1577278831915

定时任务执行第六次 30s后,移除缓存数据c

2019-12-25 21:00:39,918 [pool-3-thread-1] INFO LocalCache 89 - 定期删除策略: 开始执行, store={c=LocalCache.Cache(value=10c, expire=1577278849915)}2019-12-25 21:00:44,919 [pool-3-thread-1] INFO LocalCache 89 - 定期删除策略: 开始执行, store={c=LocalCache.Cache(value=10c, expire=1577278849915)}2019-12-25 21:00:49,918 [pool-3-thread-1] INFO LocalCache 89 - 定期删除策略: 开始执行, store={c=LocalCache.Cache(value=10c, expire=1577278849915)}2019-12-25 21:00:49,919 [pool-3-thread-1] INFO LocalCache 94 - 定期删除策略: 移除超时失效数据, key=c, value=10c, time=15772788499152019-12-25 21:00:54,918 [pool-3-thread-1] INFO LocalCache 89 - 定期删除策略: 开始执行, store={}

源码 package com.core.mall.config.cache;import lombok.Data;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.concurrent.*;/** * 本地缓存服务 * key = 字符串 | value = 字符串 | expire = 秒(有效时间) * * put 添加缓存 * get 读取缓存值 * * 失效策略: * 1. 定期删除策略:启动1个线程,每2分钟扫描一次,超时数据移除 * 2. 懒惰淘汰策略:每次访问时校验有效性,如果失效移除 */public class LocalCache { private final static Logger logger = LoggerFactory.getLogger(LocalCache.class); /** * 启动开始后延迟5秒执行时效策略 */ private static final int INITIAL_DELAY_TIME = 5; /** * 执行时效策略间隔时间 */ private static final int PERIOD_TIME = 5; /** * 本地缓存map */ private static ConcurrentHashMap<String, Cache> store; /** * 执行时效策略线程池 */ private final static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); /* * 静态代码块 * * 初始化缓存map * 添加时效策略定时线程任务 */ static { store = new ConcurrentHashMap<>(); executor.scheduleAtFixedRate(new Task(), INITIAL_DELAY_TIME, PERIOD_TIME, TimeUnit.SECONDS); } public static void put(String key, String value) { put(key, value, 0); } /** * 设置缓存 * @param key 唯一key * @param value 值 * @param expire 超时时间-单位(s/秒) */ public static void put(String key, String value, long expire) { logger.info("添加缓存,key={}, value={}, expire={}秒", key, value, expire); if (expire > 0) { store.put(key, new Cache(value, expire)); } else { store.put(key, new Cache(value)); } } public static String get(String key) { Cache cache = store.get(key); if (cache == null) { return null; } if (cache.getExpire() > 0 && cache.getExpire() < System.currentTimeMillis()) { remove(key); return null; } return store.get(key).getValue(); } private static void remove(String key) { Cache cache = store.remove(key); logger.info("懒惰淘汰策略: 移除超时失效数据, cache={}", cache); } private static void removeAll() { logger.info("定期删除策略: 开始执行, store={}", store); for (String key : store.keySet()) { Cache cache = store.get(key); if (cache.getExpire() > 0 && cache.getExpire() < System.currentTimeMillis()) { store.remove(key); logger.info("定期删除策略: 移除超时失效数据, key={}, value={}, time={}", key, cache.getValue(), cache.getExpire()); } } } /** * 定时移除时效数据任务 */ private static class Task implements Runnable { @Override public void run() { try { LocalCache.removeAll(); } catch (Exception e) { logger.info("定期删除策略异常", e); } } } /** * 本地缓存对象 */ @Data private static class Cache { private String value; private long expire = 0; Cache(String value, long expire) { this.value = value; this.expire = System.currentTimeMillis() + expire * 1000; } Cache(String value) { this.value = value; } }} 联系方式

如果对你有帮助,可以关注作者支持一下,每天会不定时回复留言(有任何问题都可以留言哦)。

微信公众号

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。