【java互联网架构】手把手教你实现线程安全并且可以设置过期时间的LRU缓存安排!( 二 )


ScheduledThreadPoolExecutor 使用的任务队列 DelayQueue 封装了一个 PriorityQueue , PriorityQueue 会对队列中的任务进行排序 , 执行所需时间短的放在前面先被执行 , 如果执行所需时间相同则先提交的任务将被先执行 。 5. 徒手撸一个线程安全的 LRU 缓存
5.1. 实现方法
ConcurrentHashMap + ConcurrentLinkedQueue +ReadWriteLock
5.2. 原理
ConcurrentHashMap 是线程安全的Map , 我们可以利用它缓存 key,value形式的数据 。 ConcurrentLinkedQueue是一个线程安全的基于链表的队列(先进先出) , 我们可以用它来维护 key。 每当我们put/get(缓存被使用)元素的时候 , 我们就将这个元素对应的 key 存放在队列尾部 , 这样就能保证队列头部的元素是最近最少使用的 。 当我们的缓存容量不够的时候 , 我们直接移除队列头部对应的key以及这个key对应的缓存即可!
另外 , 我们用到了ReadWriteLock(读写锁)来保证线程安全 。
5.3. put方法具体流程分析
为了方便大家理解 , 我将代码中比较重要的 put(key,value)方法的原理图画了出来 , 如下图所示:

【java互联网架构】手把手教你实现线程安全并且可以设置过期时间的LRU缓存安排!
本文插图

5.4. 源码/** *@authorshuang.kou *
*使用ConcurrentHashMap+ConcurrentLinkedQueue+ReadWriteLock实现线程安全的LRU缓存 *这里只是为了学习使用 , 本地缓存推荐使用 Guava 自带的 。 使用Spring的话 , 推荐使用SpringCache */ publicclassMyLruCache
{ /** *缓存的最大容量 */ privatefinalintmaxCapacity; privateConcurrentHashMap
cacheMap; privateConcurrentLinkedQueuekeys; /** *读写锁 */ privateReadWriteLockreadWriteLock=newReentrantReadWriteLock(); privateLockwriteLock=readWriteLock.writeLock(); privateLockreadLock=readWriteLock.readLock(); publicMyLruCache(intmaxCapacity){ if(maxCapacity
(maxCapacity); keys=newConcurrentLinkedQueue<>(); } publicVput(Kkey,Vvalue){ //加写锁 writeLock.lock(); try{ //1.key是否存在于当前缓存 if(cacheMap.containsKey(key)){ moveToTailOfQueue(key); cacheMap.put(key,value); returnvalue; } //2.是否超出缓存容量 , 超出的话就移除队列头部的元素以及其对应的缓存 if(cacheMap.size()==maxCapacity){ System.out.println("maxCapacityofcachereached"); removeOldestKey(); } //3.key不存在于当前缓存 。 将key添加到队列的尾部并且缓存key及其对应的元素 keys.add(key); cacheMap.put(key,value); 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); } } publicintsize(){ returncacheMap.size(); } }


推荐阅读