【java互联网架构】手把手教你实现线程安全并且可以设置过期时间的LRU缓存安排!( 三 )
非并发环境测试:
本文插图
并发环境测试:
我们初始化了一个固定容量为 10 的线程池和count为10的CountDownLatch 。 我们将100次操作分10次添加到线程池, 然后我们等待线程池执行完成这10次操作 。
本文插图
6. 实现一个线程安全并且带有过期时间的 LRU 缓存
实际上就是在我们上面时间的LRU缓存的基础上加上一个定时任务去删除缓存 , 常见的实现定时任务的方式有下面几种:
Timer :不被推荐 , 多线程会存在问题 。
ScheduledExecutorService :定时器线程池 , 可以用来替代 Timer
DelayQueue :延时队列
quartz :一个很火的开源任务调度框架 , 很多其他框架都是基于 quartz 开发的 , 比如当当网的elastic-job就是基于quartz二次开发之后的分布式调度解决方案
......
最终我们选择了 ScheduledExecutorService , 主要原因是它易用(基于DelayQueue做了很多封装)并且基本能满足我们的大部分需求 。
我们在我们上面实现的线程安全的 LRU 缓存基础上 , 简单稍作修改即可!我们增加了一个方法:
本文插图
我们put元素的时候 , 如果通过这个方法就能直接设置过期时间 。
完整源码如下:/** *@authorshuang.kou *
*使用ConcurrentHashMap+ConcurrentLinkedQueue+ReadWriteLock+ScheduledExecutorService实现线程安全的LRU缓存 *这里只是为了学习使用 , 本地缓存推荐使用Guava自带的 , 使用Spring的话 , 推荐使用SpringCache */ publicclassMyLruCacheWithExpireTime
{ /** *缓存的最大容量 */ privatefinalintmaxCapacity; privateConcurrentHashMap
cacheMap; privateConcurrentLinkedQueuekeys; /** *读写锁 */ privateReadWriteLockreadWriteLock=newReentrantReadWriteLock(); privateLockwriteLock=readWriteLock.writeLock(); privateLockreadLock=readWriteLock.readLock(); privateScheduledExecutorServicescheduledExecutorService; publicMyLruCacheWithExpireTime(intmaxCapacity){ if(maxCapacity
(maxCapacity); keys=newConcurrentLinkedQueue
0){ removeAfterExpireTime(key,expireTime); } returnvalue; }finally{ writeLock.unlock(); } } publicVget(Kkey){ //加读锁 readLock.lock(); try{ //key是否存在于当前缓存 if(cacheMap.containsKey(key)){ //存在的话就将key移动到队列的尾部 moveToTailOfQueue(key); returncacheMap.get(key); } //不存在于当前缓存中就返回Null returnnull; }finally{ readLock.unlock(); } } publicVremove(Kkey){ writeLock.lock(); try{ //key是否存在于当前缓存 if(cacheMap.containsKey(key)){ //存在移除队列和Map中对应的Key keys.remove(key); returncacheMap.remove(key); } //不存在于当前缓存中就返回Null returnnull; }finally{ writeLock.unlock(); } } /** *将元素添加到队列的尾部(put/get的时候执行) */ privatevoidmoveToTailOfQueue(Kkey){ keys.remove(key); keys.add(key); } /** *移除队列头部的元素以及其对应的缓存(缓存容量已满的时候执行) */ privatevoidremoveOldestKey(){ KoldestKey=keys.poll(); if(oldestKey!=null){ cacheMap.remove(oldestKey); } } privatevoidremoveAfterExpireTime(Kkey,longexpireTime){ scheduledExecutorService.schedule(()->{ //过期后清除该键值对 cacheMap.remove(key); keys.remove(key); },expireTime,TimeUnit.MILLISECONDS); } publicintsize(){ returncacheMap.size(); } }
推荐阅读
- 互联网分析师于斌|对于陆正耀“背后”的愉悦资本来说,反思才是第一要务
- 互联网的一些事|QuestMobile:2020 移动互联网人均使用时长同比增长 12.9%
- 互联网的放大镜TB|vivo X50Pro发布,小米10瞬间不香了?
- |传统互联网产品经理正在消失,如何自救?
- |搜狐畅游的修仙往事:当互联网公司开始“拜神信教”
- 互联网乱侃先生|国产机们不用再看高通脸色?超级芯片巨头入场,GPU比高通强很多
- 基建新基建按下互联网保险“加速键” 慧择头部效应凸显
- 36氪|36氪独家|TCL旗下工业互联网平台「格创东智」获云锋基金亿元级A轮融资
- 互联网生活|不一般!世童科技品牌启动暨智能学习桌新品发布会惊艳中山
- 互联网乱侃秀|都说苹果没5G落后国产机了,结局却很让人扎心,销量又是第一
