Java缓存技术(java内置缓存,redis,Ehcache,Caffeine的基本使用方法及其介绍)

目录

摘要

1. Java缓存技术概述

1.1定义

1.2 优势

1.3 应用场景

2. Java中的内置缓存实现

2.1 通过通过HashMap和ConcurrentHashMap实现缓存

3. Java缓存框架

3.1 Redis

3.1.1 redis的简介

3.1.4 Redis的工作原理

3.1.5 总结

3.2  Ehcache

3.2.1 Ehcache的简介

3.2.2 Ehcache的简单使用

3.2.3 数据的持久化

3.2.4 总结

3.3  Caffeine

3.3.1 Caffeine的简介

3.3.2 Caffeine的简单使用

3.3.3 caffeine总结

4. 报告总结

摘要

缓存,作为提升系统性能的关键策略,在Java编程环境中扮演着重要角色。本报告聚焦于Java缓存技术,深入探讨了其基本概念、应用场景及多样化实现。

报告首先明确了缓存的定义,并强调了其在读操作频繁、数据计算复杂及数据更新不频繁等场景下的显著优势。在Java中,缓存的实现方式多样,包括利用本地数据结构实现的本地缓存、借助Java标准库提供的缓存功能。

此外,报告还介绍了几个广受欢迎的Java缓存框架,如Redis(高性能分布式内存缓存)、Ehcache(开源Java缓存框架,支持分布式缓存)以及Caffeine(高性能Java内存缓存库,专注于快速响应和高效内存利用)。这些框架各具特色,为开发者提供了丰富的选择空间。

通过本报告的阐述,读者将全面理解Java缓存技术的核心概念、应用场景及实现方式,为优化系统性能提供有力的理论与实践支持。

  1.  Java缓存技术概述

1.1定义

缓存是数据访问的加速器,它为数据提供了一个快速的临时栖息地,以减少数据检索的时间消耗。在Java编程中,缓存技术是提升数据处理速度和系统性能的关键工具。它利用内存这一高速存储介质,保存数据的副本,以便快速访问,避免了对较慢存储设备(如硬盘)的频繁访问。

对于需要频繁访问相同数据的应用,Java缓存技术显得尤为重要。它像一座桥梁,连接了对快速数据的需求和较慢的数据存储,减少了对数据源的直接访问,提高了数据处理的效率。

简而言之,Java中的缓存技术是一种高效的数据处理策略,它利用内存的高速访问特性,为应用程序提供了快速的数据检索服务,从而提高了系统的响应速度和用户体验。这种技术不仅减轻了系统的资源负担,还为数据的快速处理和有效利用提供了新的途径。

1.2 优势

1. 提高响应速度:通过在快速的存储介质中保存数据副本,缓存减少了数据检索时间,从而加快了应用程序的响应速度。

2. 减轻后端负载:缓存减少了对数据库或其他数据源的访问次数,从而减轻了后端系统的负担。

3. 提升用户体验:更快的数据访问速度和更流畅的交互显著提升了用户的体验。

4. 降低成本:缓存减少了对昂贵资源(如数据库查询)的依赖,有助于降低运营成本。

1.3 应用场景

1. 数据库缓存:

  1. 在高并发访问的系统中,数据库压力可能非常大。为了缓解数据库压力,可以使用缓存来存储常用的查询结果。当再次访问这些数据时,可以直接从缓存中读取,而无需查询数据库,从而显著提高系统的响应速度。
  2. 缓存还可以用于存储数据库中的临时数据,如会话信息、用户登录状态等,以避免频繁访问数据库。
  1. Web应用缓存:
  1. 在Web应用中,缓存可以用于存储静态资源(如图片、CSS、JavaScript等)和动态内容(如网页、API响应等)。
  2. 通过缓存静态资源,可以减少对服务器的请求次数,降低服务器负载,提高网页加载速度。
  3. 对于动态内容,可以使用缓存来存储重复的查询结果或计算结果,以减少数据库查询和计算的时间。
  1.  分布式系统缓存:
  1. 在分布式系统中,缓存可以用于实现分布式锁、分布式会话共享等功能。
  2. 通过使用分布式锁,可以确保多个进程或线程在访问共享资源时的同步性。
  3. 分布式会话共享则允许多个服务器共享用户的会话信息,从而提供一致的用户体验。

4.  CDN缓存:

  1. 内容分发网络(CDN)中的缓存用于存储和分发静态内容(如图片、视频、音频等)。
  2. 通过将内容缓存在CDN节点上,可以缩短用户访问内容的距离和时间,提高内容的加载速度和可用性。

5.  应用层缓存:

  1. 在应用层,缓存可以用于存储应用程序的临时数据、计算结果或中间状态。
  2. 这有助于减少应用程序对后端服务的请求次数,提高应用程序的响应速度和性能。
  1. 硬件缓存:
  1. 在计算机硬件中,缓存(如CPU缓存、硬盘缓存等)用于加速数据的访问速度。
  2. 通过将常用数据存储在离处理器更近的缓存中,可以减少对慢速存储设备的访问次数,提高系统的整体性能。

  1.  Java中的内置缓存实现

2.1 通过通过HashMapConcurrentHashMap实现缓存

Java 提供了多种基础数据结构,其中 HashMap 和 ConcurrentHashMap 特别适合用于构建内存缓存。HashMap 是一个高效的哈希表实现,而 ConcurrentHashMap 则在此基础上进一步优化,专为多线程环境设计,能够提供卓越的并发访问性能。

然而,这些数据结构有一个共同的局限性:它们不支持数据持久化。因此,当应用程序重启时,所有存储在其中的缓存数据都会丢失。

在特定场景下,如果需要对某些操作进行更精细的控制,以确保其原子性,那么 ConcurrentHashMap 可能无法完全满足需求。此时,开发者可能需要考虑使用更复杂的原子操作,或者将 ConcurrentHashMap 与其他并发控制工具(如锁机制)结合使用,以实现所需的数据一致性和完整性。

以下是简单的代码实现:

public class ConcurrentMyCache {private Map<String, Object> cache = new ConcurrentHashMap<>();public void put(String key, Object value) {cache.put(key, value);}public Object get(String key) {return cache.get(key);}public void remove(String key) {cache.remove(key);}public void clear() {cache.clear();}public int size() {return cache.size();}
}public class MyCache  {private Map<String, Object> cache = new HashMap<>();// 向缓存中放入键值对public void put(String key, Object value) {cache.put(key, value);}// 从缓存中获取值public Object get(String key) {return cache.get(key);}// 从缓存中移除键值对public void remove(String key) {cache.remove(key);}// 清空缓存public void clear() {cache.clear();}// 获取缓存大小public int size() {return cache.size();}}@SpringBootTestclass CacheTest {@Testvoid testCache(){ConcurrentMyCache cache=new ConcurrentMyCache();cache.put("key1","zhangsan");cache.put("key2","lisi");System.out.println("key1: " + cache.get("key1"));System.out.println("key2: " + cache.get("key2"));MyCache cache1=new MyCache();cache1.put("key3","wangwu");cache1.put("key4","lht");System.out.println("key3: " + cache1.get("key3"));System.out.println("key4: " + cache1.get("key4"));}}

  1.  Java缓存框架

3.1 Redis

3.1.1 redis的简介

Redis是一个完全开源免费的高性能(NOSQL)的key-value数据库。它遵守BSD协议,使用ANSI C语言编写,并支持网络和持久化。Redis拥有极高的性能,每秒可以进行11万次的读取操作和8.1万次的写入操作。它支持丰富的数据类型,包括String、Hash、List、Set和Ordered Set,并且所有的操作都是原子性的。此外,Redis还提供了多种特性,如发布/订阅、通知、key过期等。Redis采用自己实现的分离器来实现高速的读写操作,效率非常高。Redis是一个简单、高效、分布式、基于内存的缓存工具,通过网络连接提供Key-Value式的缓存服务。

Redis可以通过配置文件设置密码参数,这样客户端连接到Redis服务就需要密码验证,从而提高Redis服务的安全性。

3.1.2 redis的简单使用

@Datapublic class User implements Serializable {private Integer id;private String username;private String password;}

通过自动装配redis里面的RedisTemplate这个类里面的相关配置并且封装方法方便后期使用。

/*** spring redis 工具类***/@SuppressWarnings(value = { "unchecked", "rawtypes" })@Componentpublic class RedisCache{@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}}

3.1.3 redis的主要特征

- 键值(key-value)型,value支持多种不同数据结构,功能丰富

- 单线程,每个命令具备原子性

- 低延迟,速度快(基于内存、IO多路复用、良好的编码)。

- 支持数据持久化

- 支持主从集群、分片集群,    

- 支持多语言客户端

3.1.4 Redis的工作原理

1. 内存存储:数据完全存储在内存中,提供快速的读写访问,时间复杂度接近O(1)。

  1. 单线程架构:采用单线程处理请求,避免了多线程带来的上下文切换和锁竞争,简化了并发控制,提高了性能。
  2. 非阻塞IO:使用多路复用IO模型,能够非阻塞地处理多个客户端请求,提高了并发处理能力。
  3. Lua脚本执行:支持在Lua脚本中执行命令,允许用户执行复杂的逻辑和操作,增加了操作的灵活性。

3.1.5 总结

Redis是一种高效的内存键值存储系统,广泛用于缓存管理、会话保持及实时数据处理等多种场景。它的优势体现在:极快的读写速度、对数据结构的多样化支持、具备持久化功能(包括RDB快照和AOF日志)、支持分布式部署,以及提供强大的原子操作特性。

3.2  Ehcache

3.2.1 Ehcache的简介

EhCache是一个高效的纯Java进程内缓存框架,支持单机和分布式缓存,适用于需要快速数据访问的场景。它具备简单易用、快速访问、多种缓存策略(如堆缓存、磁盘缓存、集群缓存)等优点。EhCache的缓存数据有两级,一级是内存,二级是磁盘,当内存不足时,数据可以自动溢出到磁盘,从而解决了容量问题。此外,EhCache还支持缓存数据在虚拟机重启时写入磁盘,以及通过RMI、可插入API等方式进行分布式缓存。

在Spring Boot中,EhCache可以通过配置文件和Bean注入来使用,提供了灵活的缓存策略配置,如缓存对象的最大数量、对象是否永不过期、空闲时间和存活时间等。同时,EhCache还提供了缓存和缓存管理器的侦听接口,支持多缓存管理器实例以及一个实例的多个缓存区域。

虽然EhCache在非集群环境下可能导致敏感数据更新延迟,但它非常适合高QPS场景和小量数据缓存需求。使用EhCache时,建议设置较短的过期时间以保证数据的及时更新。

3.2.2 Ehcache的简单使用

首先,需要初始化一个缓存管理器(CacheManager),利用它来创建新的缓存或者访问已有的缓存。之后,可以在这些缓存中存储数据,或者从缓存中检索数据。

@Testpublic void test() {// 初始化 CacheManagerCacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()// 一个CacheManager可以管理多个Cache.withCache("ehcacheDemo",CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class,String.class,// heap相当于设置数据在堆内存中存储的 个数 或者 大小ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, MemoryUnit.MB).build()).build()).build(true);// 如果 CacheManagerBuilder.build(); 如果没有传参数,需要手动调用init()// cacheManager.init();// 基于 CacheManager 获取 Cache对象Cache<String, String> ehCache = cacheManager.getCache("ehcacheDemo", String.class, String.class);// 放去缓存ehCache.put("ehcache", "hello ehcache");// 取System.out.println(ehCache.get("ehcache"));}

EhCache 提供了非常灵活和强大的配置选项,这使得它能够适应各种不同的缓存需求。

<config xmlns="http://www.ehcache.org/v3"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd"><!--定义缓存--><cache alias="squaredNumber"uses-template="myTemplate"><!--缓存使用的缓存模板的名称--><key-type>java.lang.Integer</key-type><value-type>java.lang.Integer</value-type><heap unit="entries">10</heap></cache><!--定义缓存模板--><cache-template name="myTemplate"><expiry><ttl unit="seconds">60</ttl><!--缓存项的过期策略,60秒过期--></expiry></cache-template>
</config>

3.2.3 数据的持久化

Ehcache还可以将数据落地本地磁盘,这样的话,当服务重启后,依然会从磁盘反序列化数据到内存中,实现数据的持久化代码如下:

@Test
public void test1() {// 声明存储位置String path = "D:\\ehcache";// 初始化 CacheManagerCacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()// 设置存储位置.with(CacheManagerBuilder.persistence(path))// 一个CacheManager可以管理多个Cache.withCache("ehcacheDemo",CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class,String.class,// heap相当于设置数据在堆内存中存储的 个数 或者 大小ResourcePoolsBuilder.newResourcePoolsBuilder()// 堆内内存.heap(10, MemoryUnit.MB)// 堆外内存// off-heap大小必须 大于 heap 设置的内存大小.offheap(15,MemoryUnit.MB)// 磁盘存储,记得添加true,才能正常持久化,并且序列号以及反序列化// disk大小必须 大于 off-heap 设置的内存.disk(20,MemoryUnit.MB,true)).build()).build(true);// 如果 CacheManagerBuilder.build(); 如果没有传参数,需要手动调用init()// cacheManager.init();// 基于 CacheManager 获取 Cache对象Cache<String, String> ehCache = cacheManager.getCache("ehcacheDemo", String.class, String.class);// 放去缓存ehCache.put("ehcache", "hello ehcache");// 取System.out.println(ehCache.get("ehcache"));// 保证数据正常持久化不丢失,记得 close()cacheManager.close();
}

3.2.4 总结

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点。EhCache支持单机缓存和分布式缓存,分布式可以理解为缓存数据的共享,这就导致内存缓存数据量偏小。ehcache缓存非常存储和读取非常快。

3.3  Caffeine

3.3.1 Caffeine的简介

Caffeine是一个高性能的Java缓存库,它通过精细的数据结构和高效的内存管理,确保了在高并发环境下的快速访问。它提供了丰富的配置选项,包括缓存的最大容量、数据失效策略和自动刷新等,以满足不同应用程序的需求。Caffeine支持同步和异步两种数据加载方式,同步加载会阻塞主线程直到数据加载完成,而异步加载则允许主线程在数据加载时继续执行,从而提高系统的并发性。此外,Caffeine还支持多种过期策略,如基于时间或访问频率,以及注册监听器来监控缓存的变更事件,为应用程序提供了更细粒度的控制和监视。总的来说,Caffeine是一个功能强大、易于使用的缓存解决方案,非常适合需要高性能缓存的Java应用程序。

3.3.2 Caffeine的简单使用

  1. 缓存加载策略
  1. Cache手动创建

最普通的一种缓存,无需指定加载方式,需要手动调用put()进行加载。需要注意的是put()方法对于已存在的key将进行覆盖,这点和Map的表现是一致的。在获取缓存值时,如果想要在缓存值不存在时,原子地将值写入缓存,则可以调用get(key, k -> value)方法,该方法将避免写入竞争。调用invalidate()方法,将手动移除缓存。

在多线程情况下,当使用get(key, k -> value)时,如果有另一个线程同时调用本方法进行竞争,则后一线程会被阻塞,直到前一线程更新缓存完成;而若另一线程调用getIfPresent()方法,则会立即返回null,不会被阻塞。

 @Testpublic void test1() {Cache<Object, Object> cache = Caffeine.newBuilder()//初始数量.initialCapacity(10)//最大条数.maximumSize(10)//expireAfterWrite和expireAfterAccess同时存在时,以expireAfterWrite为准//最后一次写操作后经过指定时间过期.expireAfterWrite(1, TimeUnit.SECONDS)//最后一次读或写操作后经过指定时间过期.expireAfterAccess(1, TimeUnit.SECONDS)//监听缓存被移除.removalListener((key, val, removalCause) -> { })//记录命中.recordStats().build();cache.put("1","张三");//张三System.out.println(cache.getIfPresent("1"));//存储的是默认值System.out.println(cache.get("2",o -> "默认值"));}
  1. Loading Cache自动创建

LoadingCache是一种自动加载的缓存。其和普通缓存不同的地方在于,当缓存不存在/缓存已过期时,若调用get()方法,则会自动调用CacheLoader.load()方法加载最新值。调用getAll()方法将遍历所有的key调用get(),除非实现了CacheLoader.loadAll()方法。使用LoadingCache时,需要指定CacheLoader,并实现其中的load()方法供缓存缺失时自动加载。

在多线程情况下,当两个线程同时调用get(),则后一线程将被阻塞,直至前一线程更新缓存完成。

   

 //Loading Cache自动创建@Testpublic void test2() {LoadingCache<String, String> loadingCache = Caffeine.newBuilder()//创建缓存或者最近一次更新缓存后经过指定时间间隔,刷新缓存;refreshAfterWrite仅支持LoadingCache.refreshAfterWrite(10, TimeUnit.SECONDS).expireAfterWrite(10, TimeUnit.SECONDS).expireAfterAccess(10, TimeUnit.SECONDS).maximumSize(10)//根据key查询数据库里面的值,这里是个lamba表达式.build(key -> new Date().toString());loadingCache.put("1","张三");//张三System.out.println(loadingCache.getIfPresent("1"));//存储的是默认值System.out.println(loadingCache.get("2",o -> "默认值"));}
  1. Async Cache异步获取

AsyncCache是Cache的一个变体,其响应结果均为CompletableFuture,通过这种方式,AsyncCache对异步编程模式进行了适配。默认情况下,缓存计算使用ForkJoinPool.commonPool()作为线程池,如果想要指定线程池,则可以覆盖并实现Caffeine.executor(Executor)方法。synchronous()提供了阻塞直到异步缓存生成完毕的能力,它将以Cache进行返回。

在多线程情况下,当两个线程同时调用get(key, k -> value),则会返回同一个CompletableFuture对象。由于返回结果本身不进行阻塞,可以根据业务设计自行选择阻塞等待或者非阻塞。

 //Async Cache异步获取@Testpublic void test3() {AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder().refreshAfterWrite(1, TimeUnit.SECONDS).expireAfterWrite(1, TimeUnit.SECONDS).expireAfterAccess(1, TimeUnit.SECONDS).maximumSize(10).buildAsync(key -> {try {// 模拟数据库查询延迟Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}// 模拟从数据库获取的数据return new Date().toString();});// 获取缓存中的值CompletableFuture<String> future = asyncLoadingCache.get("1");// 当获取完成时,打印结果future.thenAccept(System.out::println);// 等待一段时间,确保异步加载完成try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}

  1. 驱逐策略

驱逐策略在创建缓存的时候进行指定。常用的有基于容量的驱逐和基于时间的驱逐。基于容量的驱逐需要指定缓存容量的最大值,当缓存容量达到最大时,Caffeine将使用LRU策略对缓存进行淘汰;基于时间的驱逐策略如字面意思,可以设置在最后访问/写入一个缓存经过指定时间后,自动进行淘汰。

  1. 基于容量的驱逐(LRU)

基于容量的驱逐是指缓存在达到一定的容量后,会按照最近最少使用(Least Recently Used)的策略自动淘汰掉一些缓存项。这通常用于限制缓存占用的内存空间。

 

//基于容量驱逐@Testpublic void maximumSizeTest() throws InterruptedException {Cache<Integer, Integer> cache = Caffeine.newBuilder()//超过10个后会使用W-TinyLFU算法进行淘汰.maximumSize(10).evictionListener((key, val, removalCause) -> {System.out.println("淘汰缓存:key:" + key + " val:" + val);}).build();for (int i = 1; i < 20; i++) {cache.put(i, i);}Thread.sleep(500);//缓存淘汰是异步的// 打印还没被淘汰的缓存System.out.println(cache.asMap());}
  1. 基于时间的驱逐

基于时间的驱逐是指缓存项在一定时间后自动被淘汰。可以基于最后一次写入时间或者最后一次访问时间来淘汰缓存项。

    /*** 访问后到期(每次访问都会重置时间,也就是说如果一直被访问就不会被淘汰)*/@Testpublic void expireAfterAccessTest() throws InterruptedException {Cache<Integer, Integer> cache = Caffeine.newBuilder().expireAfterAccess(1, TimeUnit.SECONDS)//可以指定调度程序来及时删除过期缓存项,而不是等待Caffeine触发定期维护//若不设置scheduler,则缓存会在下一次调用get的时候才会被动删除.scheduler(Scheduler.systemScheduler()).evictionListener((key, val, removalCause) -> {log.info("淘汰缓存:key:{} val:{}", key, val);}).build();cache.put(1, 2);System.out.println(cache.getIfPresent(1));Thread.sleep(3000);System.out.println(cache.getIfPresent(1));//null
  1. 刷新机制

Caffeine 缓存库提供了灵活的刷新机制,可以在缓存项即将过期时自动刷新数据,以确保缓存数据的时效性。refreshAfterWrite()表示x秒后自动刷新缓存的策略可以配合淘汰策略使用,注意的是刷新机制只支持LoadingCache和AsyncLoadingCache。

//刷新机制private static int NUM = 0;@Testpublic void refreshAfterWriteTest() throws InterruptedException {LoadingCache<Integer, Integer> cache = Caffeine.newBuilder().refreshAfterWrite(1, TimeUnit.SECONDS)//模拟获取数据,每次获取就自增1.build(integer -> ++NUM);//获取ID=1的值,由于缓存里还没有,所以会自动放入缓存System.out.println(cache.get(1));// 1// 延迟2秒后,理论上自动刷新缓存后取到的值是2// 但其实不是,值还是1,因为refreshAfterWrite并不是设置了n秒后重新获取就会自动刷新// 而是x秒后&&第二次调用getIfPresent的时候才会被动刷新Thread.sleep(2000);System.out.println(cache.getIfPresent(1));// 1//此时才会刷新缓存,而第一次拿到的还是旧值System.out.println(cache.getIfPresent(1));// 2}
  1. 统计

Caffeine 缓存库提供了内置的统计功能,可以帮助开发者监控和调优缓存性能。通过启用统计功能,你可以收集关于缓存操作的详细信息,例如命中率、未命中率、加载次数、加载时间等。

 

 //统计@Testpublic void requestCount(){LoadingCache<String, String> cache = Caffeine.newBuilder()//创建缓存或者最近一次更新缓存后经过指定时间间隔,刷新缓存;refreshAfterWrite仅支持LoadingCache.refreshAfterWrite(1, TimeUnit.SECONDS).expireAfterWrite(1, TimeUnit.SECONDS).expireAfterAccess(1, TimeUnit.SECONDS).maximumSize(10)//开启记录缓存命中率等信息.recordStats()//根据key查询数据库里面的值.build(key -> {Thread.sleep(1000);return new Date().toString();});cache.put("1", "shawn");cache.get("1");/** hitCount :命中的次数* missCount:未命中次数* requestCount:请求次数* hitRate:命中率* missRate:丢失率* loadSuccessCount:成功加载新值的次数* loadExceptionCount:失败加载新值的次数* totalLoadCount:总条数* loadExceptionRate:失败加载新值的比率* totalLoadTime:全部加载时间* evictionCount:丢失的条数*/System.out.println(cache.stats());

3.3.3 caffeine总结

Caffeine是一个高性能的Java缓存库,它提供了丰富的配置选项和强大的缓存策略,包括最近最少使用(LRU)、最近最不常用(LFU)、先进先出(FIFO)等。它支持自动刷新、定时失效、大小限制和异步加载,确保了数据的时效性和缓存的高效性。Caffeine还内置了统计监控功能,帮助开发者了解缓存性能并进行调优。其线程安全、易于集成和使用,是提升Java应用性能的理想选择。

4. 报告总结

本报告深入探讨了Java缓存技术,包括其定义、优势、应用场景及实现方式。缓存通过在内存中存储数据副本,减少了对慢速存储设备的访问,从而加速了数据检索,提高了系统性能。Java提供了多种缓存实现,如利用HashMap和ConcurrentHashMap构建本地缓存,以及使用Redis、Ehcache和Caffeine等缓存框架。这些框架支持不同的缓存策略,如堆缓存、磁盘缓存、集群缓存,以及自动刷新和过期策略。Caffeine特别受到关注,它是一个高性能的Java缓存库,提供了丰富的配置选项,包括定时失效、大小限制、同步和异步加载,以及多种过期策略。Caffeine还内置了统计监控功能,帮助开发者优化缓存性能。报告通过介绍这些技术和框架,为读者提供了理论与实践相结合的缓存解决方案,以优化系统性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/453543.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图的最小生成树算法--普里姆(Prim)算法和克鲁斯克尔(Kruskal)算法

一、图的最小生成树 最小生成树&#xff08;Minimum spanning tree&#xff0c;MST&#xff09;是最小权重生成树&#xff08;Minimum weight spanning tree&#xff09;的简称&#xff0c;是一个连通加权无向图中一棵权值最小的生成树。 在一给定的无向图 G ( V , E ) G …

探索 Jupyter 笔记本转换的无限可能:nbconvert 库的神秘面纱

文章目录 探索 Jupyter 笔记本转换的无限可能&#xff1a;nbconvert 库的神秘面纱背景&#xff1a;为何选择 nbconvert&#xff1f;库简介&#xff1a;nbconvert 是什么&#xff1f;安装指南&#xff1a;如何安装 nbconvert&#xff1f;函数用法&#xff1a;简单函数示例应用场…

MySQL企业常见架构与调优经验分享

文章目录 一、选择 PerconaServer、MariaDB 还是 MYSQL二、常用的 MYSQL 调优策略三、MYSOL 常见的应用架构分享四、MYSOL 经典应用架构 观看学习课程的笔记&#xff0c;分享于此~ 课程&#xff1a;MySQL企业常见架构与调优经验分享 mysql官方优化文档 一、选择 PerconaServer、…

全方面熟悉Maven项目管理工具(二)坐标、pom.xml文件的解读!

1. 坐标&#xff08;核心概念&#xff09; 1.1 数学中的坐标 使用 x、y、z 三个向量作为空间的坐标系&#xff0c;可以在空间中唯一的定位到一个点 1.2 Maven 中的坐标 1.2.1 向量说明&#xff1a; 使用三个向量在 Maven的仓库 中唯一的定位到一个 jar 包 groupId&#xf…

【某农业大学计算机网络实验报告】实验四 路由信息协议RIP

实验目的&#xff1a; 1&#xff0e;深入了解RIP协议的特点和配置方法&#xff1a;通过此次实验&#xff0c;掌握RIP协议作为一种动态路由协议的基本工作原理&#xff0c;了解其距离向量算法的核心概念&#xff0c;以及如何在网络设备上配置RIP协议&#xff1b; 2.验证RIP协议…

AndroidStudio实验报告——实验一、二

目录 实验一&#xff1a; AS安装与安卓环境搭建 一、实验目标 二、实验内容 &#xff08;一&#xff09;Android Studio安装 &#xff08;二&#xff09;JDK安装与配置 &#xff08;三&#xff09;Android SDK安装与配置 三、实验结果&#xff1a;&#xff08;实…

【Java】正则表达式详解

目录 引言 一、基本概念 1.1 元字符 1.2 预定义字符类 1.3 边界匹配符 1.4 数量标识符 1.5 捕获与非捕获分组 二、Java中的正则表达式支持 三、正则表达式的使用示例 3.1 匹配字符串 3.2 替换字符串 3.3 分割字符串 3.4 使用Pattern和Matcher 3.5 捕获组和后向…

局域网——Prim Kruskal

题目 Prim &#xff08;生成一颗包含起点的最小生成树&#xff0c;所以要多次调用&#xff09; #include <bits/stdc.h>using namespace std;const int N 510; const int inf 0x3f3f3f3f;int n, m; int g[N][N], dis[N]; bool p[N], vis[N];int prim (int u) {memset(…

分布式检测线路、精准定位故障:输电线路故障定位监测系统

分布式检测线路、精准定位故障&#xff1a;输电线路故障定位监测系统 随着电力行业的快速发展和电网规模的不断扩大&#xff0c;输电线路作为电力传输的“生命线”&#xff0c;其安全稳定运行对于保障电力供应、促进经济社会发展具有重要意义。然而&#xff0c;输电线路通常暴…

[云] Deploying Your First Serverless Application

• Goal: • Hands-on lab to get started with Serverless • Agenda: • Deploying Your First Serverless Application • Assignment Introduction Create and test function in AWS Lambda • Lets create an addition function using AWS Lambda. • To create the addi…

HCIP-HarmonyOS Application Developer 习题(十六)

&#xff08;判断&#xff09;1、HiLink通过分布式软总线的方式连接所有设备&#xff0c;强能力设备可对弱能力设备进行设备虚拟化&#xff0c;将弱设备当做本机设备直接调用。 答案&#xff1a;错误 分析&#xff1a;HiLink 主要针对的是应用开发者与第三方设备开发者&#xf…

100种算法【Python版】第1篇——贪心策略

贪心是一种策略 1 策略内核1.1 基本思想1.2 策略步骤1.3 贪心算法举例说明1.3.1 活动选择问题1.3.2 01背包问题1.3.3 最优解分析 2 贪心策略的应用2.1 应用&#xff1a;计算单源最短路径2.2 应用&#xff1a;霍夫曼编码字符串 3 策略优缺点3.1 优点3.2 缺点3.3 总结 1 策略内核…

助力语音技术发展,景联文科技提供语音数据采集服务

语音数据采集是语音识别技术、语音合成技术以及其他语音相关应用的重要基础。采集高质量的语音数据有助于提高语音识别的准确性&#xff0c;同时也能够促进语音技术的发展。 景联文科技作为专业的数据采集标注公司&#xff0c;支持语音数据采集。可通过手机、专业麦克风阵列、专…

快速了解Python流程控制语句基本使用

&#x1f600;前言 在编程中&#xff0c;流程控制语句是用于控制程序执行顺序的关键部分。通过条件判断和循环机制&#xff0c;程序能够根据不同的情况选择执行特定的代码块&#xff0c;或重复执行某段代码。本文将详细介绍 Python 中常见的流程控制语句&#xff0c;包括 if、i…

JS事件和DOM

1. DOM 1.1 基本概念 DOM&#xff0c;全称 Document Object Model&#xff0c;即文档对象模型。它是 Web 上最常用的 API 之一&#xff0c;是加载在浏览器中的文档模型&#xff0c;可以将文档表示为节点树&#xff08;或称 DOM 树&#xff09;&#xff0c;其中每个节点代表文…

缓存常见问题:缓存穿透、雪崩、击穿及解决方案分析

1. 什么是缓存穿透&#xff0c;怎么解决&#xff1f; 缓存穿透是指用户请求的数据在缓存中不存在即没有命中&#xff0c;同时在数据库中也不存在&#xff0c;导致用户每次请求该数据都要去数据库中查询一遍。如果有恶意攻击者不断请求系统中不存在的数据&#xff0c;会导致短时…

Java面试场景题(1)---如何使用redis记录上亿用户连续登陆天数

感谢uu们的观看&#xff0c;话不多说开始~ 对于这个问题&#xff0c;我们需要先来了解一下~ 海量数据都可以用bitmap来存储&#xff0c;因为占得内存小&#xff0c;速度也很快 我大概计算了一下~ 完全够&#xff1a;String类型512M 1byte 8个bit位 8个状态 512M1024byt…

计算机组成原理(笔记7高速缓冲存储器Cache,计算机组成原理的重难点全、直接、组相连)

为什么要设立高速缓冲存储器 &#xff08;Cache&#xff09;&#xff1f; Cache是介于CPU和主存之间的小容量存储器&#xff0c;存取速度比主存快。它能高速地向CPU提供指令和数据&#xff0c;加快程序的执行速度。它是为了解决CPU和主存之间速度不匹配而采用的一项重要技术。…

01 一篇读懂25机械考研复试超全流程讲解|考研面试经验和面试真题快来背诵!

复试面试流程及经验汇总篇 千万不要小瞧出成绩前的准备以及最常见面试问题你提前熟记于心&#xff0c;面试再遇到&#xff0c;能够有逻辑有条理的回答出不是空洞的话&#xff0c;给导师的印象分就肯定高。 考研复试面试最全最完整的实用攻略&#xff0c;从出考研初试成绩前到…

《深度学习》模型的部署、web框架 服务端及客户端案例

目录 一、模型的部署 1、模型部署的定义与目的 1&#xff09;定义 2&#xff09;目的 2、模型部署的步骤 1&#xff09;导出模型 2&#xff09; 部署模型 3&#xff09;测试模型 4&#xff09;监控模型 3、模型部署的方式 1&#xff09;云端部署 2&#xff09;嵌入…