手把手教你实现线程安全并且可以设置过期时间的LRU缓存。安排!

本文介绍了如何实现一个线程安全且具有过期时间的LRU缓存。文章讲解了LRU缓存的基本概念,以及使用ConcurrentLinkedQueue、ReadWriteLock和ScheduledExecutorService等技术来确保线程安全和添加过期时间功能。通过源码分析和并发测试,展示了如何利用这些工具创建高效、安全的缓存解决方案。
摘要由CSDN通过智能技术生成

目录:

  • 1. LRU 缓存介绍

  • 2. ConcurrentLinkedQueue简单介绍

  • 3. ReadWriteLock简单介绍

  • 4.ScheduledExecutorService 简单介绍

  • 5. 徒手撸一个线程安全的 LRU 缓存

  • 6. 实现一个线程安全并且带有过期时间的 LRU 缓存

很多人就会问了:“网上已经有这么多现成的缓存了!为什么面试官还要我们自己实现一个呢?” 。咳咳咳,当然是为了面试需要。哈哈!开个玩笑,我个人觉得更多地是为了学习吧!

  1. 实现一个线程安全的 LRU 缓存

  2. 实现一个线程安全并且带有过期时间的 LRU 缓存

考虑到了线程安全性我们使用了 ConcurrentHashMap 、ConcurrentLinkedQueue这两个线程安全的集合。另外,还用到 ReadWriteLock(读写锁)。为了实现带有过期时间的缓存,我们用到了 ScheduledExecutorService来做定时任务执行。 1. LRU 缓存介绍 LRU (Least Recently Used,最近最少使用)是一种缓存淘汰策略。 LRU缓存指的是当缓存大小已达到最大分配容量的时候,如果再要去缓存新的对象数据的话,就需要将缓存中最近访问最少的对象删除掉以便给新来的数据腾出空间。 2. ConcurrentLinkedQueue简单介绍 ConcurrentLinkedQueue是一个基于单向链表的无界无锁线程安全的队列,适合在高并发环境下使用,效率比较高。 我们在使用的时候,可以就把它理解为我们经常接触的数据结构——队列,不过是增加了多线程下的安全性保证罢了。和普通队列一样,它也是按照先进先出(FIFO)的规则对接点进行排序。 另外,队列元素中不可以放置null元素。 ConcurrentLinkedQueue 整个继承关系如下图所示:

编辑切换为居中

添加图片注释,不超过 140 字(可选)

ConcurrentLinkedQueue中最主要的两个方法是:offer(value)和poll(),分别实现队列的两个重要的操作:入队和出队(offer(value)等价于add(value))。 我们添加一个元素到队列的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素。

编辑

添加图片注释,不超过 140 字(可选)

单链表 利用ConcurrentLinkedQueue队列先进先出的特性,每当我们 put/get(缓存被使用)元素的时候,我们就将这个元素存放在队列尾部,这样就能保证队列头部的元素是最近最少使用的。 3. ReadWriteLock简单介绍 ReadWriteLock 是一个接口,位于 java.util.concurrent.locks包下,里面只有两个方法分别返回读锁和写锁:

编辑

添加图片注释,不超过 14

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮您写一个Go语言的LRU缓存,以下是示例代码: ``` package main import ( "container/list" "fmt" "time" ) type CacheItem struct { key string value interface{} expired_at time.Time } type LRUCache struct { capacity int items map[string]*list.Element list *list.List } func NewLRUCache(capacity int) *LRUCache { return &LRUCache{ capacity: capacity, items: make(map[string]*list.Element), list: list.New(), } } func (c *LRUCache) Get(key string) (interface{}, bool) { if elem, ok := c.items[key]; ok { item := elem.Value.(*CacheItem) if item.expired_at.IsZero() || item.expired_at.After(time.Now()) { c.list.MoveToFront(elem) return item.value, true } else { c.list.Remove(elem) delete(c.items, key) } } return nil, false } func (c *LRUCache) Set(key string, value interface{}, expired time.Duration) { if elem, ok := c.items[key]; ok { c.list.MoveToFront(elem) elem.Value.(*CacheItem).value = value elem.Value.(*CacheItem).expired_at = time.Now().Add(expired) } else { if len(c.items) >= c.capacity { tail := c.list.Back() if tail != nil { delete(c.items, tail.Value.(*CacheItem).key) c.list.Remove(tail) } } elem := c.list.PushFront(&CacheItem{key, value, time.Now().Add(expired)}) c.items[key] = elem } } func main() { cache := NewLRUCache(2) cache.Set("key1", "value1", time.Second*5) cache.Set("key2", "value2", time.Second*10) cache.Set("key3", "value3", time.Second*15) if value, ok := cache.Get("key1"); ok { fmt.Println("key1:", value) } else { fmt.Println("key1 not found") } if value, ok := cache.Get("key2"); ok { fmt.Println("key2:", value) } else { fmt.Println("key2 not found") } if value, ok := cache.Get("key3"); ok { fmt.Println("key3:", value) } else { fmt.Println("key3 not found") } } ``` 这个LRU缓存可以设置过期时间,当缓存中的数据过期时,会自动删除。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值