简单的LRU本地缓存实现-Java版本

ops/2024/10/21 3:49:09/

在这里插入图片描述

文章目录

  • 什么是缓存
    • 缓存的种类
    • 缓存的关键特性
    • 缓存的优势与挑战
      • 优势:
      • 挑战:
    • 缓存的应用场景
    • 什么是LRUCache
    • LRU 缓存的工作原理
    • 核心操作
    • 为何选择 LRU
    • 使用场景
  • 一个简单的LRU缓存实现
  • 相关资料
    • 基础资料

什么是缓存

缓存(Cache)是一种高速数据存储层,它可以存储临时数据副本,让未来的请求能够更快地访问这些数据。缓存存在的主要目的是提高数据访问速度和提升系统的整体性能。缓存中的数据通常来源于原始数据的一个子集,这些原始数据可能存储在一个较慢的存储系统中,比如硬盘驱动器或远程数据库。

缓存的种类

  1. 硬件与软件缓存
  • 硬件缓存:CPU缓存是一种高速存储器,能够暂存从主存储器(RAM)中读取的数据,从而加快数据访问速度。
  • 软件缓存:在软件开发中,可以实现多种类型的缓存策略来存储经常访问的数据或结果,如Web页面缓存、数据库缓存等。
  1. 客户端缓存和服务器端缓存
  • 客户端缓存,如Web浏览器缓存,存储静态页面,以减少数据的重复下载。
  • 服务器端缓存,如数据库查询缓存,存储常见查询结果或计算结果,以减少数据库访问次数和计算负担。
  1. 分布式缓存
    分布式缓存系统,如Redis和Memcached,提供了一个由多台服务器组成的缓存池,可以大幅提高缓存容量和处理能力。

缓存的关键特性

  1. 数据一致性:缓存数据与源数据在更新时需要保持一致,否则可能会出现数据过时的问题。
  2. 缓存淘汰策略:当缓存容量不足时,需要通过一定的策略删除部分缓存数据,常见策略有最近最少使用(LRU)、最不经常使用(LFU)等。

缓存的优势与挑战

优势:

减少了对原始数据源(如数据库)的访问次数,降低了系统的整体负载。
减少了数据访问的延迟,提供了更快的响应时间。
提高了资源的利用效率,可以通过缓存复用之前的计算结果。

挑战:

缓存与数据源之间的一致性管理。
缓存数据的过期策略和淘汰策略。
分布式缓存中的数据分片和同步问题。

缓存的应用场景

  • Web应用:缓存静态页面、图片、JavaScript文件等,减少服务器的计算和带宽消耗。
  • 数据库系统:缓存频繁执行的查询结果,减少数据库的查询次数。
  • 大数据处理:缓存中间结果,加快大数据计算和分析过程。

总的来说,缓存是提升系统性能、加快数据访问速度的关键技术之一。合理地设计和使用缓存可以极大提升应用程序的性能和用户体验。然而,也需要小心处理缓存带来的数据一致性和管理挑战。

什么是LRUCache

最近最少使用(LRU)缓存是一种常见的缓存策略,用以管理在有限的缓存空间中存储的数据。LRU 缓存的核心思想是当缓存达到最大容量时,优先移除最长时间未被访问的数据条目,为新的数据条目腾出空间。这种策略基于“局部性原理”,即最近被访问过的数据项未来被再次访问的概率较高。

LRU 缓存的工作原理

LRU 缓存使用一种数据结构来同时维护数据条目的插入顺序和访问顺序。这通常通过结合使用哈希表和双向链表来实现:

哈希表用于快速查找和访问缓存中的数据条目,达到近乎 O(1) 的访问时间复杂度。
双向链表用于维护所有数据条目的访问顺序。链表的头部代表了最近被访问的数据,而链表的尾部代表了最久未被访问的数据。

核心操作

  1. 访问数据(get):
    当访问一个数据项时,如果该项在缓存中,则需要将其移动到双向链表的头部,表示该数据项是最近被访问过的。
    如果数据项不在缓存中,则返回null或者相应的指示。
  2. 添加/更新数据(put):
    当插入一个新的数据项时,该数据项被放置在双向链表的头部,表示最近被访问过。同时,该数据项的键和寻址信息被存储在哈希表中。
    如果缓存达到最大容量,则需要从双向链表的尾部移除一个数据项,并且在哈希表中删除相应的项。
    如果插入的是一个现存的数据项(更新操作),则将该数据项移动到双向链表的头部,并更新哈希表中的值。

为何选择 LRU

LRU 缓存策略的优势在于其简洁而有效的机制,能够在保持缓存空间高效使用的同时,确保了频繁访问的数据可以快速被检索。这对于提高应用性能、降低数据访问延迟具有显著效果。

使用场景

LRU 缓存在各种场景中都有应用,特别是在需要快速访问数据的场合,如:

总之,LRU 缓存是一种广泛使用的缓存淘汰策略,通过优先移除最长时间未被访问的数据项,它能有效管理有限的缓存空间,并提高数据访问效率。

一个简单的LRU缓存实现


import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;/*** A simple LRU cache implementation based on LinkedHashMap.* @param <K>* @param <V>*/
public class LRUCache<K, V> {private final LinkedHashMap<K, CacheEntry<V>> cache;private final int maxSize;private final long maxLifetimeMillis;/*** 构造器 LRUCache(final int maxSize, final long maxLifetime, final TimeUnit maxLifetimeUnit):** 创建一个 LRUCache 实例,并设置缓存的最大容量 maxSize 和元素的最大生存时间(maxLifetimeMillis,由 maxLifetime 和 maxLifetimeUnit 转换而来)。* 如果 maxSize 或 maxLifetime 是非正数,则会抛出 IllegalArgumentException 异常。* 缓存中元素的添加是基于 LinkedHashMap 的 access-order(访问顺序),即最近访问的元素会被放到队尾。* @param maxSize* @param maxLifetime* @param maxLifetimeUnit*/public LRUCache(final int maxSize, final long maxLifetime, final TimeUnit maxLifetimeUnit) {if (maxSize <= 0) {throw new IllegalArgumentException("maxSize must be positive");}if (maxLifetime <= 0) {throw new IllegalArgumentException("maxLifetime must be positive");}this.maxSize = maxSize;this.maxLifetimeMillis = maxLifetimeUnit.toMillis(maxLifetime);this.cache = new LinkedHashMap<K, CacheEntry<V>>(maxSize, 0.75f, true) {protected boolean removeEldestEntry(Map.Entry<K, CacheEntry<V>> eldest) {long now = System.currentTimeMillis();V value = eldest.getValue().value;long creationTime = eldest.getValue().creationTime;// Remove the oldest item if either the cache size is exceeded// or if the oldest item's lifetime is expiredreturn (size() > LRUCache.this.maxSize)|| ((now - creationTime) > LRUCache.this.maxLifetimeMillis);}};}/*** 将键值对存入缓存中,如果键或值为空则抛出 NullPointerException。* 如果缓存已满或某个元素过期,这个方法还会触发缓存中最旧的元素被清除(通过 LinkedHashMap 内部的 removeEldestEntry 方法定义)。* @param key* @param value*/public void put(K key, V value) {long now = System.currentTimeMillis();if (key == null || value == null) {throw new NullPointerException("key and value must not be null");}synchronized (cache) {cache.put(key, new CacheEntry<>(value, now));}}/*** 从缓存中获取键对应的值,如果不存在则存入默认值 defaultValue 并返回。* @param key* @param defaultValue* @return*/public V get(K key, V defaultValue) {synchronized (cache) {V value = get(key);if (value == null) {put(key, defaultValue);return defaultValue;}return value;}}/*** 从缓存中移除指定键及其对应的值。* @param key*/public void invalidate(K key) {synchronized (cache) {cache.remove(key);}}/*** 移除并返回缓存中指定键对应的值。* @param key* @return*/public V remove(K key) {synchronized (cache) {CacheEntry<V> entry = cache.remove(key);return entry == null ? null : entry.value;}}/*** 根据给定的键获取对应的值,并根据元素的生存时间判断是否过期;如果没有过期,则返回值并更新元素在缓存中的位置(访问顺序),否则从缓存中删除该元素并返回 null。* @param key* @return*/public V get(K key) {synchronized (cache) {long now = System.currentTimeMillis();CacheEntry<V> entry = cache.get(key);if (entry != null && (now - entry.creationTime) <= maxLifetimeMillis) {// LinkedHashMap access-order policy will move the entry to the endreturn entry.value;} else {cache.remove(key);return null;}}}/*** 分别返回缓存中所有值的集合。* @return*/public Set<V> values() {synchronized (cache) {return cache.values().stream().map(e -> e.value).collect(Collectors.toSet());}}/*** 分别返回缓存中所有键的集合。* @return*/public Set<K> keys() {synchronized (cache) {return cache.keySet();}}/*** 判断缓存中是否包含指定键的元素,同时检查该元素是否过期。* @param key* @return*/public boolean containsKey(K key) {synchronized (cache) {return cache.containsKey(key) && (System.currentTimeMillis() - cache.get(key).creationTime) <= maxLifetimeMillis;}}/*** 清空缓存中的所有元素。*/public void clear() {synchronized (cache) {cache.clear();}}/*** 获取缓存当前的大小。* @return*/public int size() {synchronized (cache) {return cache.size();}}/*** 获取缓存当前的最大容量。* @return*/public int getMaxSize() {return maxSize;}private static class CacheEntry<V> {final V value;final long creationTime;CacheEntry(V value, long creationTime) {this.value = value;this.creationTime = creationTime;}}
}

相关资料

缓存技术在计算机科学和软件工程中扮演着至关重要的角色,特别是在提高应用性能、降低数据访问延迟和减轻后端系统负载方面。以下是关于缓存的一些关键资料和资源,包括定义、类型、策略、工具和最佳实践。

基础资料

  1. 缓存定义和原理:
  • “计算机组织与设计 - 硬件/软件接口”(David A. Patterson 和 John L. Hennessy),这本书详细讲述了计算机体系结构中缓存的基础概念和设计。
  • MDN Web Docs中的“HTTP 缓存”,提供基于Web的缓存机制、策略和控制方法的深入解析(网址:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching )。
    缓存类型:
  1. 客户端缓存,例如浏览器缓存
  1. 实现和工具
  • 分布式缓存系统:
    Redis:一个开源的使用内存存储数据的数据结构服务器,可以用作数据库、缓存和消息中间件(网址:https://redis.io/ )。

  • Memcached:一个高性能的分布式内存对象缓存系统,旨在加速动态Web应用程序通过减轻数据库负载(网址:http://memcached.org/ )。
    本地缓存库:

  • Guava Cache:谷歌的Java编程库Guava提供了一个强大的内存缓存机制,支持多种缓存过期策略和缓存淘汰策略(网址:https://github.com/google/guava/wiki/CachesExplained )。

  • Caffeine:一个Java 8的高性能缓存库,被认为是Guava Cache的后继者(网址:https://github.com/ben-manes/caffeine )。


http://www.ppmy.cn/ops/4880.html

相关文章

QML 中引用 js 文件闪退问题

问题描述 在移植 Android 中遇到这样一个引用兼容性问题&#xff0c;起因是这样的&#xff0c;Windows 版本的采用了 QML 分离的方式加载&#xff0c;而 Android 版本又采用了 qrc 的方式。而 Qt 中的机制是采用 QML 分离方式时则使用相对路径的方式引用 js 文件&#xff0c;而…

购物车实现

目录 1.购物车常见的实现方式 2.购物车数据结构介绍 3.实例分析 1.controller层 2.service层 1.购物车常见的实现方式 方式一&#xff1a;存储到数据库 性能存在瓶颈方式二&#xff1a;前端本地存储 localstorage在浏览器中存储 key/value 对&#xff0c;没有过期时间。s…

计算机网络之同轴电缆,集线器,网桥,交换机,路由器

ping的过程 两台主机用交叉线连接&#xff0c;通过88.2ping88.3发现底层是先经过广播&#xff0c;通过arp协议&#xff0c;告诉我要找的ip是88.3,然后88.3主机收到后就把自己的mac地址发送回去&#xff0c;同理88.2发现是发给自己的后就进行接收&#xff0c;有了mac地址然后再通…

利用AQS(AbstractQueuedSynchronizer)实现一个线程同步器

目录 1. 前言 2. 什么是同步器 3. 同步器实现思路 Semaphore(信号量) 4. 代码实现 4.1. 创建互斥锁类 4.2 编写静态内部类&#xff0c;继承AQS 4.3 内部类实现AQS钩子函数 4.3 封装lock&#xff0c;unlock方法 4.4. 测试 5. 总结 本文章源码仓库&#xff1a;Conc…

javaWeb项目-智能仓储系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、JSP技术 JSP(Jav…

混合现实(MR)开发框架

混合现实&#xff08;MR&#xff09;开发框架为开发者提供了构建MR应用程序所需的基本工具和功能。它们通常包括3D引擎、场景图、输入系统、音频系统、网络功能以及支持同时处理现实世界和虚拟世界信息的功能。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&…

虚拟机磁盘剩余空间不足

VMware 弹出提示&#xff1a; 对文件“E:\Virtual Machine\CentOS 7 1810 的克隆 (2)\CentOS 7 1810-cl1.vmdk”的操作失败。 如果该文件位于远程文件系统上&#xff0c;请确保网络连接以及该磁盘所在的服务器正常工作。如果该文件位于可移动介质中&#xff0c;请重新连接该介…

大数据平台搭建2024(一)

一&#xff1a;基础配置 创建虚拟机并查出ip地址进行连接 ip a1.配置node01静态ip地址与主机名 vi /etc/sysconfig/network-scripts/ifcfg-ens33修改或添加如下内容&#xff1a; BOOTPROTO"static" ONBOOTyes #根据虚拟机网卡信息配置 IPADDR192.168.200.141 NET…