3.7 Java中本地缓存实现

缓存框架jetcache+本地缓存Caffeine jetcache框架 阅读详情


1.简介

1.1 为什么要Cache

  • 降低数据库的访问压力.
  • 提高查询的性能,改善用户体验.

1.2 你都了解哪些Cache?

  • 浏览器缓存
  • 数据持久层的Cache(MyBatis中的Cache设计)
  • 逻辑处理层的Cache(Spring中的Cache)
  • CPU的高速缓存

1.3 对本地缓存你会如何设计

  • 数据的存储结构(散列存储)
  • 数据的淘汰算法(FIFO,LRU)
  • 任务调度策略(定时刷新缓存)
  • 缓存日志的记录(命中率)
  • GC时会缓存数据的影响

2.本地缓存的设计

2.1 Cache接口设计

我们在设计Cache时,一般会先设计一个接口,定义一套规范,例如:

package com.jt.cache;

/**
 * Cache 接口规范设计
 */
public interface Cache {
    /**
     * 存储数据
     * @param key
     * @param value
     */
    void putObject(Object key,Object value);

    /**
     * 基于key获取数据
     * @param key
     * @return
     */
    Object getObject(Object key);

    /**
     * 移除指定key的数据
     * @param key
     * @return
     */
    Object removeObject(Object key);

    /**
     * 清空缓存
     */
    void clear();

    /**
     * 获取缓存中数据的个数
     * @return
     */
    int size();
    //...
}

2.2 Cache默认存储设计

设计一个Cache的默认存储对象,主要用于存储数据,例如:

package com.jt.cache;

import java.util.HashMap;
import java.util.Map;

public class DefaultCache implements  Cache{
    private Map<Object,Object> cache=new HashMap<>();
    @Override
    public void putObject(Object key, Object value) {
         cache.put(key,value);
    }

    @Override
    public Object getObject(Object key) {
        return cache.get(key);
    }

    @Override
    public Object removeObject(Object key) {
        return cache.remove(key);
    }

    @Override
    public void clear() {
         cache.clear();
    }

    @Override
    public int size() {
        return cache.size();
    }

    @Override
    public String toString() {
        return "DefaultCache{" +
                "cache=" + cache.toString() +
                '}';
    }

    public static void main(String[] args) {
        Cache cache=new DefaultCache();
        cache.putObject("A",100);
        cache.putObject("B",200);
        cache.putObject("C",300);
        System.out.println(cache);
    }
}

2.3 SynchronizedCache 设计及实现

线程安全的Cache设计及实现,例如:

package com.jt.cache;

public class SynchronizedCache implements Cache {
    private Cache cache;

    public SynchronizedCache(Cache cache) {
        this.cache = cache;
    }

    @Override
    public synchronized void putObject(Object key, Object value) {
        cache.putObject(key, value);
    }

    @Override
    public synchronized Object getObject(Object key) {
        return cache.getObject(key);
    }

    @Override
    public synchronized Object removeObject(Object key) {
        return cache.removeObject(key);
    }

    @Override
    public void clear() {
        cache.clear();
    }

    @Override
    public int size() {
        return cache.size();
    }

    @Override
    public String toString() {
        return "SynchronizedCache{" +
                "cache=" + cache +
                '}';
    }

    public static void main(String[] args) {
        Cache cache = new SynchronizedCache(new DefaultCache());
        cache.putObject("A", 100);
        cache.putObject("B", 200);
        System.out.println(cache);
    }
}

2.4 LoggingCache 设计及实现

实际工作中我们经常要分析和监控缓存的命中率,例如我们设计了缓存,但为什么还是查询了数据库,有多少请求数据来自缓存,多少请求查询了数据库等,此时需要一个基于日志进行分析的一个过程,因此LoggingCache对象诞生,例如:

package com.jt.cache;

/**
 * 通过此对象记录Cache命中率
 */
public class LoggingCache implements Cache{
    /**对这个cache进行命中率的记录*/
    private Cache cache;
    /**请求次数*/
    private int requests;
    /**命中的次数*/
    private int hints;
    public LoggingCache(Cache cache){
        this.cache=cache;
    }

    @Override
    public void putObject(Object key, Object value) {
         cache.putObject(key,value);
    }
    @Override
    public Object getObject(Object key) {
        //1.记录请求次数
        requests++;
        //2.从cache获取数据
        Object object = cache.getObject(key);
        if(object!=null){
            //计算命中率
            hints++;
            System.out.println("hits/requests is "+hints*1.0/requests);
        }
        return object;
    }
    @Override
    public Object removeObject(Object key) {
        return cache.removeObject(key);
    }

    @Override
    public void clear() {
       cache.clear();
    }
    @Override
    public int size() {
        return cache.size();
    }

    public static void main(String[] args) {
        LoggingCache loggingCache =
                new LoggingCache(new DefaultCache());
        loggingCache.putObject("A",100);
        loggingCache.putObject("B",200);
        loggingCache.putObject("C",300);
        loggingCache.getObject("D");
        loggingCache.getObject("A");
        loggingCache.getObject("A");
    }
}

2.5 FifoCache设计及实现

缓存可以提供的内存空间是有限的,在缓存满的时候,我们要提供一些数据淘汰策略,接下来我们基于FIFO算法,对缓存进行设计,例如:

package com.jt.cache;

import java.util.Deque;
import java.util.LinkedList;

/**
 * 有界缓存淘汰策略:FIFO(先进先出)算法
 */
public class FifoCache implements Cache{
    /**存储数据的Cache*/
    private Cache cache;
    /**Cache的最大容量*/
    private int maxCap;
    /**双端队列(两头都可以操作),基于此队列记录key的顺序*/
    private Deque<Object> deque;
    public FifoCache(Cache cache, int maxCap) {
        this.cache = cache;
        this.maxCap = maxCap;
        this.deque=new LinkedList<>();
    }
    @Override
    public void putObject(Object key, Object value) {
        //1.记录key的顺序
        deque.addLast(key);
        //2.判定cache是否已满,满了则移除元素
        //if(cache.size()==maxCap){} 方式1
        if(deque.size()>maxCap){//方式2
            //获取最先放入的元素key
            Object eldestKey=deque.removeFirst();
            //移除最先放进去的元素
            cache.removeObject(eldestKey);
        }
        //3.添加新的元素
        cache.putObject(key,value);
    }
    @Override
    public Object getObject(Object key) {
        return cache.getObject(key);
    }

    @Override
    public Object removeObject(Object key) {
        Object value=cache.removeObject(key);
        deque.remove(key);
        return value;
    }

    @Override
    public void clear() {
        cache.clear();
        deque.clear();
    }

    @Override
    public int size() {
        return cache.size();
    }

    @Override
    public String toString() {
        return "FifoCache{" +
                "cache=" + cache +
                '}';
    }

    public static void main(String[] args) {
        FifoCache cache = new FifoCache(new DefaultCache(), 3);
        cache.putObject("A",100);
        cache.putObject("B",200);
        cache.putObject("C",300);
        cache.putObject("D",400);
        cache.putObject("E",500);
        System.out.println(cache);
    }
}

2.6 LruCache 设计及实现

基于LRU算法(最近最少使用算法)对缓存进行数据淘汰设计,例如:

package com.cy.java.cache;  
import java.util.LinkedHashMap;  
import java.util.Map;  
  
/** 缓存淘汰策略:LRU(最近最少使用算法)*/  
public class LruCache implements Cache {  
 private Cache cache;  
 /**通过此属性记录要移除的数据对象*/  
 private Object eldestKey;  
 /**通过此map记录key的访问顺序*/  
 private Map<Object,Object> keyMap;  
 @SuppressWarnings("serial")  
 public LruCache(Cache cache,int maxCap) {  
 this.cache=cache;  
//LinkedHashMap可以记录key的添加顺序或者访问顺序  
 this.keyMap=new LinkedHashMap<Object,Object>(maxCap, 0.75f, true)
 {//accessOrder  
//此方法每次执行keyMap的put操作时调用  
@Override  
protected boolean removeEldestEntry (java.util.Map.Entry<Object, Object> eldest) {  
boolean isFull=size()>maxCap;  
if(isFull)eldestKey=eldest.getKey();  
return isFull;  
}  
 };  
}  
@Override  
public void putObject(Object key, Object value) {  
//存储数据对象  
cache.putObject(key, value);  
//记录key的访问顺序,假如已经满了,就要从cache中移除数据  
keyMap.put(key, key);//此时会执行keyMap对象的removeEldestEntry  
if(eldestKey!=null) {  
cache.removeObject(eldestKey);  
eldestKey=null;  
}  
}  
@Override  
public Object getObject(Object key) {  
keyMap.get(key);//记录key的访问顺序  
return cache.getObject(key);  
}  
  
@Override  
public Object removeObject(Object key) {  
return cache.removeObject(key);  
}  
  
@Override  
public void clear() {  
cache.clear();  
keyMap.clear();  
}  
@Override  
public int size() {  
return cache.size();  
}  
@Override  
public String toString() {  
return cache.toString();  
}  
  
public static void main(String[] args) {  
SynchronizedCache cache=  
 new SynchronizedCache(  
new LoggingCache(  
new LruCache(new PerpetualCache(),3)));  
cache.putObject("A", 100);  
cache.putObject("B", 200);  
cache.putObject("C", 300);  
cache.getObject("A");  
cache.getObject("C");  
cache.putObject("D", 400);  
cache.putObject("E", 500);  
System.out.println(cache);  
  
}  
}

3.总结(Summary)

本章节为基础拓展章节,重点是通过本地缓存的设计,加强Java中一些基础点的理解,同时在Java缓存设计上做一个拔高.

SpringBoot 集成 Caffeine 实现本地缓存 Caffeine 官网Caffeine 是基于Java 1.8 的高性能本地缓存库,同样是 Google 开发的,由 Guava 改进而来,底层设计思路、功能和使用方式与 Guava 非常类似,但是各方面的性能都要远远超过前者,可以看做是 Guava cache 的升级版。而且在 Spring5 开始的默认缓存实现就将 Caffeine 代替原来的 Google Guava,官方说明指出,其缓存命中率已经接近最优值@Data@Service@Autowired// 模拟数据库数据。 阅读详情

相关推荐

使用Caffeine实现高效本地缓存

本文详细介绍了如何使用Caffeine实现高效的本地缓存,包括其核心特性、使用场景、在Spring Boot中的集成方法,以及如何与Redis结合实现一二级缓存。通过合理使用本地缓存,可以显著提升系统性能,降低后端服务压力。在实际项目中,建议根据具体业务场景选择合适的缓存策略,并注意缓存一致性问题。

lingding_cn的专栏 931

Redis基础(七)—Java中本地缓存实现(拓展练习)

一、简介 1、为什么要Cache 降低数据库的访问压力。 提高查询的性能,改善用户体验。 2、你都了解哪些Cache? 浏览器缓存 数据持久层的Cache(MyBatis中的Cache设计) 逻辑处理层的Cache(Spring中的Cache) CPU的高速缓存 3、对本地缓存你会如何设计 数据的存储结构(散列存储) 数据的淘汰算法(FIFO,LRU) 任务调度策略(定时刷新缓存) 缓存日志的记录(命中率) GC时会缓存数据的影响 二、本地缓存的设计 1、Cache接口设计(缓存规范设计) 我们在设计Cac

AimerDaniel的博客 514

Java+YOLOv10云边协同架构:破解无人货架商品识别与库存同步痛点

无人货架的核心,从来不是用多先进的模型,而是要保证稳定、快速、低成本的运营。全云端架构听起来美好,但一上量就会遇到识别慢、丢数据、成本高的问题;云边协同架构,把实时性要求高的放在边缘,把非实时的放在云端,既保证了本地卖货的稳定性,又实现了云端的全局管控,是无人货架的最优解。这套架构不是什么高深的技术,而是把我们8年的无人货架项目经验,做了标准化、模块化的封装,从边缘端的Java推理,到云端的模型更新,全链路打通,真正给客户降本增效。

2601_94871597的博客 385

实现 Java 本地缓存,该从这几点开始

缓存,我相信大家对它一定不陌生,在项目中,缓存肯定是必不可少的。市面上有非常多的缓存工具,比如 Redis、Guava Cache 或者 EHcache。对于这些工具,我想大家肯定都非常熟悉,所以今天我们不聊它们,我们来聊一聊如何实现本地缓存。参考上面几种工具,要实现一个较好的本地缓存,平头哥认为要从以下三个方面开始。 1、存储集合的选择 实现本地缓存,存储容器肯定是 key/value 形式的数...

平头哥的技术博文 9647

orbit-db-cache:orbit-db的本地缓存

轨道数据库缓存 orbit-db的本地缓存 orbit-db使用的同构缓存,对于浏览器使用level.js (indexedDB),对于节点使用leveldown (leveldb)实现。 该项目用在: 。 安装 该项目使用和 npm install --save orbit-db-cache 原料药 公开方法 get 从缓存存储中获取项目 set 为高速缓存存储区中的给定键设置一个值 del 从缓存存储中删除给定的键值 贡献 如果您认为这样会更好,请提出! 请注意,@ orbitdb中的所有交互均属于我们的行为准则。 执照 麻省理工学院:copyright:2017-2018 Protocol Labs Inc.,Haja Networks Oy

如何利用URDF文件表示并联结构(仅适用于支持SDF格式的仿真环境)

介绍了一种使用URDF文件在Gazebo中表示并联结构的方法,该方法使用了URDF的SDF拓展。在一个具有并联结构的双足机器人上应用并演示了此方法的有效性。

RobotFreak的博客 3835

【java缓存、redis缓存、guava缓存】java中实现缓存的几种方式

java中实现缓存

Ez4Sterben的博客 5241

奇安信 2025 年护网蓝队初选笔试题(附答案解析)

熬夜为大家整理了 奇安信 2025 年护网蓝队初选笔试题,(关注我我会持续更新)涵盖 SQL 注入、Web 安全、渗透测试、二进制安全 等核心知识点,并附上详细答案解析,助力大家高效备考!12.下列关于虚表指针描述正确的是(1.5分)✅ B. 虚表指针存储的是虚表的首地址❌ A. 任何类对象都存在虚表指针(仅含虚函数的类有)❌ C. 虚表指针位于对象内存空间的起始处(由编译器决定)❌ D. 虚表指针是否存在不影响对象所占内存空间的大小(存在时会增加指针大小)📌 解析:虚表指针(vptr)用于实现多态,指向

Aishenyanying33的博客 4686

基于Java使用HashMap<String,List<String>>实现数据的缓存

1.最近任务需要将数据进行不断比较并输出数据,数据是多条,利用HashMap和List结合实现数据缓存。 代码如下: public class MapTest { public class MapTest { private static HashMapList> mapSave = new HashMap<>(); public static void main(Str

fengzhimohan的博客 9065

训练AI:从数据收集到模型部署的完整指南

如果你刚开始接触AI,建议先学习一些基础的编程和机器学习知识,还可以使用现成的AI平台和工具来帮助你训练AI模型。在这篇文章中,我们将详细探讨从数据收集到模型部署的完整步骤,并提供一些有用的技巧和工具,以帮助你成功地训练自己的AI模型。在收集数据时,你需要从可靠的数据源(如数据仓库、数据集市、API接口)获取数据,确保数据的准确性和完整性。常用的划分比例是70%的数据集用于训练模型、15%的数据集用于验证模型,5%的数据集用于超参数调整,最后10%的数据集用于测试模型的性能。测试数据集用于测试模型的性能。

a_wsnd的博客 4156

华为无线AP+AC(ensp)

VLAN 100--192.168.100.0/24为AP的管理IP地址VLAN10--192.168.10.0/24为无线用户获取的IP地址在DHCP Server(LSW3)上查看地址分配情况。

abcdlalal的博客 1万+

Java基于【S3】协议实现游标分页查询

游标分页(Marker)是S3官方推荐方案,海量文件下性能稳定,适配后台列表、前端滚动加载场景。本文提供可直接上线的游标分页代码,支持目录筛选、文件名模糊检索、文件/文件夹区分

cqscf的博客 448

WS2812和homeassistant握手

本文学习了WS2812和homeassistant握手,后期会分享更多有趣物联网的操作从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。...

vor234的博客 807

Java实现本地缓存

java实现本地缓存 缓存 缓存,将程序或系统中重复用到的数据缓存在内存中,加快访问速度,减少系统开销,提高系统效率的方案。 数据存储方式主要分2种: 文件 数据保存在文件中,做持久化。 内存 数据保存在内存中,也就是创建一个静态内存区域,本文中数据保存在静态区域,使用MAP保存key\value数据。 开源缓存框架 Redis Redis是基于内存、可持久化的日志型、Key-Value数据...

王佳楠的专栏 6292

Xilinx ISE系列教程(2):LED点灯工程、仿真、bit下载和mcs固化

bit流生成配置选项很多,支持生成bit/bin/ascii格式的bin文件,是否压缩,配置速度,配置管脚的上下拉,用户ID,数据加载速度,SPI总线宽度,是否支持Readback,程序加密等等。,在之后的文章,我们会以Xilinx Spartan-6系列FPGA XC6SLX16为例,不涉及FPGA开发知识,仅仅是工具的使用,介绍Xilinx ISE开发环境的使用教程和使用技巧。bit文件下载之后,可以看到LED按照我们设计的1s周期闪烁起来了,但是此时如果断电,重新上电程序就丢失了。...

whik1194的博客 2265

2021年03月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

给定一个十进制正整数n(0 < n < 1000000000),每个数位上数字均不为0。n的位数为m。现在从m位中删除k位(0

人生就是一个不断学习的过程 1000

Springboot3 + Springboot cache+Ehcache3 + Redisson 实现本地缓存管理及分布式本地缓存更新方案

使用ehcache3+redisson,实现本地缓存配置管理及分布本地缓存更新方案。项目使用springboot3.1.7 gradle8.5。2)cache配置 jcache -----application.properties。两个服务80与8080端口,80端口服务更新数据,两个服务订阅变更消息更新缓存;1)开启注解 -----spingboot启动类或配置类。再次测试80服务数据变更后,获取数据取本地缓存,超时后取数据库。核心逻辑:采用redisson 发布订阅模式同步变更消息。

qq_42492038的博客 3601

汇川Easy系列PID_AT指令弹簧质量阻尼系统闭环控制仿真测试

汇川Easy系列PLC系统PID指令(温度控制PID应用编程)

RXXW_Dor的博客 746

java实现本地缓存

本文从实现本地缓存的设计角度,一起简单的探讨了一下实现本地缓存需要注意的地方,其实这些也是缓存的核心技术,不管是 Redis、Guava Cache 还是 EHcache或者其他缓存工具,它们在实现原理上,跟我们本地缓存的实现原理都差不多。只要我们理解了本地缓存的实现原理,在去学习这些缓存工具,我相信还是会比较轻松的。 缓存 缓存,将程序或系统中重复用到的数据缓存在内存中,加快访问速度,减少系统开销,提高系统效率的方案。 数据存储方式主要分2种: 文件 数据保存在文件中,做持久化。 内存 数据

Java后端技术栈 2722

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

java web 系列:本地缓存

目录: 一:什么是缓存 二:为什么要用本地缓存 三:我们一开始是怎么实施本地缓存的 四:Java本地缓存标准 五:Java开源缓存框架 六:再次实现本地缓存 一:什么是缓存 所谓缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例。这样做可以减少系统开销,提高系统效率。 缓存主要可分为二大类: 1:通过文件缓存,顾名思义文件...

lkb的博客 763

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

java本地缓存_java缓存——(五)LocalCache本地缓存分享

LocalCache本地缓存分享前言一、本地缓存应用场景二、java本地缓存标准三、java开源缓存框架四、LocalCache实现结束语前言本次分享探讨java平台的本地缓存,是指占用JVM的heap区域来缓冲存储数据的缓存组件。一、本地缓存应用场景localcache有着极大的性能优势:1. 单机情况下适当使用localcache会使应用的性能得到很大的提升。2. 集群环境下对于敏感性要求不高...

weixin_39802962的博客 1985

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Java8-本地缓存

这里我将会给大家演示用ConcurrentHashMap类和lambda表达式实现一个本地缓存。因为Map有一个新的方法可以在key为Null的时候自动计算一个新的value值。非常完美的实现cache。来看下代码: public static void main(String[] args) { for (int i = 0; i < 10; i++) System.o

踏雁寻花 2934

java local cache_LocalCache在Java项目中如何实现本地缓存

LocalCache在Java项目中如何实现本地缓存发布时间:2020-11-19 15:39:25来源:亿速云阅读:79作者:Leah今天就跟大家聊聊有关LocalCache在Java项目中如何实现本地缓存,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、本地缓存应用场景localcache有着极大的性能优势:1. 单机情况下适当使用lo...

weixin_34300871的博客 860

Java8简单的本地缓存实现

这里我将会给大家演示用ConcurrentHashMap类和lambda表达式实现一个本地缓存。因为Map有一个新的方法,在key为Null的时候自动计算一个新的value值。非常适合实现cache。来看下代码: public static void main(String[] args) { for (int i = 0; i < 10; i++) ...

75

Java本地缓存之Caffeine

Caffeine 是基于 Java 8 的高性能本地缓存库,由 Google Guava 缓存改进而来。高并发读取: Caffeine 的读性能接近 ConcurrentHashMap需要自动加载: LoadingCache 支持自动加载需要过期策略: 支持灵活的过期策略需要统计监控: 内置统计功能。

deathnote0415的专栏 1062
上一篇: 3.6 Redis在SpringBoot工程中的综合应用
下一篇: 3.8 Redis问题总结
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值