Java缓存技能(java内置缓存,redis,Ehcache,Caffeine的根本利用方法及其 ...

打印 上一主题 下一主题

主题 837|帖子 837|积分 2511

目次

摘要
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缓存技能的焦点概念、应用场景及实现方式,为优化体系性能提供有力的理论与实践支持。


  •  Java缓存技能概述
1.1界说
缓存是数据访问的加快器,它为数据提供了一个快速的临时栖息地,以减少数据检索的时间斲丧。在Java编程中,缓存技能是提升数据处理速度和体系性能的关键工具。它利用内存这一高速存储介质,保存数据的副本,以便快速访问,制止了对较慢存储设备(如硬盘)的频繁访问。
对于必要频繁访问相同数据的应用,Java缓存技能显得尤为重要。它像一座桥梁,连接了对快速数据的需求和较慢的数据存储,减少了对数据源的直接访问,提高了数据处理的效率。
简而言之,Java中的缓存技能是一种高效的数据处理计谋,它利用内存的高速访问特性,为应用程序提供了快速的数据检索服务,从而提高了体系的响应速度和用户体验。这种技能不仅减轻了体系的资源负担,还为数据的快速处理和有效利用提供了新的途径。
1.2 优势
1. 提高响应速度:通过在快速的存储介质中保存数据副本,缓存减少了数据检索时间,从而加快了应用程序的响应速度。
2. 减轻后端负载:缓存减少了对数据库或其他数据源的访问次数,从而减轻了后端体系的负担。
3. 提升用户体验:更快的数据访问速度和更流畅的交互显著提升了用户的体验。
4. 低落成本:缓存减少了对昂贵资源(如数据库查询)的依赖,有助于低落运营成本。
1.3 应用场景
1. 数据库缓存:

  • 在高并发访问的体系中,数据库压力可能非常大。为了缓解数据库压力,可以利用缓存来存储常用的查询效果。当再次访问这些数据时,可以直接从缓存中读取,而无需查询数据库,从而显著提高体系的响应速度。
  • 缓存还可以用于存储数据库中的临时数据,如会话信息、用户登录状态等,以制止频繁访问数据库。

  • Web应用缓存:

  • 在Web应用中,缓存可以用于存储静态资源(如图片、CSS、JavaScript等)和动态内容(如网页、API响应等)。
  • 通过缓存静态资源,可以减少对服务器的请求次数,低落服务器负载,提高网页加载速度。
  • 对于动态内容,可以利用缓存来存储重复的查询效果或计算效果,以减少数据库查询和计算的时间。

  •  分布式体系缓存:

  • 在分布式体系中,缓存可以用于实现分布式锁、分布式会话共享等功能。
  • 通过利用分布式锁,可以确保多个进程或线程在访问共享资源时的同步性。
  • 分布式会话共享则答应多个服务器共享用户的会话信息,从而提供一致的用户体验。
4.  CDN缓存:

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

  • 在应用层,缓存可以用于存储应用程序的临时数据、计算效果或中间状态。
  • 这有助于减少应用程序对后端服务的请求次数,提高应用程序的响应速度和性能。

  • 硬件缓存:

  • 在计算机硬件中,缓存(如CPU缓存、硬盘缓存等)用于加快数据的访问速度。
  • 通过将常用数据存储在离处理器更近的缓存中,可以减少对慢速存储设备的访问次数,提高体系的团体性能。



  •  Java中的内置缓存实现
2.1 通过通过HashMapConcurrentHashMap实现缓存
Java 提供了多种基础数据结构,此中 HashMap 和 ConcurrentHashMap 特别适适用于构建内存缓存。HashMap 是一个高效的哈希表实现,而 ConcurrentHashMap 则在此基础上进一步优化,专为多线程情况设计,能够提供杰出的并发访问性能。
然而,这些数据结构有一个共同的局限性:它们不支持数据持久化。因此,当应用程序重启时,全部存储在此中的缓存数据都会丢失。
在特定场景下,如果必要对某些操纵进行更精细的控制,以确保其原子性,那么 ConcurrentHashMap 可能无法完全满足需求。此时,开发者可能必要考虑利用更复杂的原子操纵,或者将 ConcurrentHashMap 与其他并发控制工具(如锁机制)结合利用,以实现所需的数据一致性和完整性。
以下是简单的代码实现:
  1. public class ConcurrentMyCache {
  2.     private Map<String, Object> cache = new ConcurrentHashMap<>();
  3.     public void put(String key, Object value) {
  4.         cache.put(key, value);
  5.     }
  6.     public Object get(String key) {
  7.         return cache.get(key);
  8.     }
  9.     public void remove(String key) {
  10.         cache.remove(key);
  11.     }
  12.     public void clear() {
  13.         cache.clear();
  14.     }
  15.     public int size() {
  16.         return cache.size();
  17.     }
  18. }
  19. public class MyCache  {
  20.     private Map<String, Object> cache = new HashMap<>();
  21.     // 向缓存中放入键值对
  22.     public void put(String key, Object value) {
  23.         cache.put(key, value);
  24.     }
  25.     // 从缓存中获取值
  26.     public Object get(String key) {
  27.         return cache.get(key);
  28.     }
  29.     // 从缓存中移除键值对
  30.     public void remove(String key) {
  31.         cache.remove(key);
  32.     }
  33.     // 清空缓存
  34.     public void clear() {
  35.         cache.clear();
  36.     }
  37.     // 获取缓存大小
  38.     public int size() {
  39.         return cache.size();
  40.     }
  41. }
  42. @SpringBootTest
  43. class CacheTest {
  44.     @Test
  45.     void testCache(){
  46.         ConcurrentMyCache cache=new ConcurrentMyCache();
  47.         cache.put("key1","zhangsan");
  48.         cache.put("key2","lisi");
  49.         System.out.println("key1: " + cache.get("key1"));
  50.         System.out.println("key2: " + cache.get("key2"));
  51.         MyCache cache1=new MyCache();
  52.         cache1.put("key3","wangwu");
  53.         cache1.put("key4","lht");
  54.         System.out.println("key3: " + cache1.get("key3"));
  55.         System.out.println("key4: " + cache1.get("key4"));
  56.     }
  57. }
复制代码



  •  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的简单利用
  1. @Data
  2. public class User implements Serializable {
  3.     private Integer id;
  4.     private String username;
  5.     private String password;
  6. }
复制代码
通过主动装配redis内里的RedisTemplate这个类内里的相关设置并且封装方法方便后期利用。
  1. /**
  2.  * spring redis 工具类
  3.  *
  4.  **/
  5. @SuppressWarnings(value = { "unchecked", "rawtypes" })
  6. @Component
  7. public class RedisCache
  8. {
  9.     @Autowired
  10. public RedisTemplate redisTemplate;
  11.  /**
  12.      * 缓存基本的对象,Integer、String、实体类等
  13.      *
  14.      * @param key 缓存的键值
  15.      * @param value 缓存的值
  16.      */
  17.     public <T> void setCacheObject(final String key, final T value)
  18.     {
  19.         redisTemplate.opsForValue().set(key, value);
  20.     }
  21.     /**
  22.      * 获得缓存的基本对象。
  23.      *
  24.      * @param key 缓存键值
  25.      * @return 缓存键值对应的数据
  26.      */
  27.     public <T> T getCacheObject(final String key)
  28.     {
  29.         ValueOperations<String, T> operation = redisTemplate.opsForValue();
  30.         return operation.get(key);
  31. }
  32. }
复制代码

3.1.3 redis的主要特征
- 键值(key-value)型,value支持多种不同数据结构,功能丰富
- 单线程,每个下令具备原子性
- 低延迟,速度快(基于内存、IO多路复用、精良的编码)。
- 支持数据持久化
- 支持主从集群、分片集群,    
- 支持多语言客户端

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

  • 单线程架构:采用单线程处理请求,制止了多线程带来的上下文切换和锁竞争,简化了并发控制,提高了性能。
  • 非阻塞IO:利用多路复用IO模型,能够非阻塞地处理多个客户端请求,提高了并发处理本领。
  • 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),利用它来创建新的缓存或者访问已有的缓存。之后,可以在这些缓存中存储数据,或者从缓存中检索数据。
  1. @Test
  2.     public void test() {
  3.         // 初始化 CacheManager
  4.         CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
  5.                 // 一个CacheManager可以管理多个Cache
  6.                 .withCache("ehcacheDemo",
  7.                         CacheConfigurationBuilder.newCacheConfigurationBuilder(
  8.                                 String.class,
  9.                                 String.class,
  10.                                 // heap相当于设置数据在堆内存中存储的 个数 或者 大小
  11.                                 ResourcePoolsBuilder.newResourcePoolsBuilder()
  12.                                         .heap(10, MemoryUnit.MB).build()).build())
  13.                 .build(true);
  14.         // 如果 CacheManagerBuilder.build(); 如果没有传参数,需要手动调用init()
  15.         // cacheManager.init();
  16.         // 基于 CacheManager 获取 Cache对象
  17.         Cache<String, String> ehCache = cacheManager.getCache("ehcacheDemo", String.class, String.class);
  18.         // 放去缓存
  19.         ehCache.put("ehcache", "hello ehcache");
  20.         // 取
  21.         System.out.println(ehCache.get("ehcache"));
  22.     }
复制代码

EhCache 提供了非常灵活和强大的设置选项,这使得它能够适应各种不同的缓存需求。
  1. <config xmlns="http://www.ehcache.org/v3"
  2.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.         xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
  4.     <!--定义缓存-->
  5.     <cache alias="squaredNumber"
  6.            uses-template="myTemplate"><!--缓存使用的缓存模板的名称-->
  7.         <key-type>java.lang.Integer</key-type>
  8.         <value-type>java.lang.Integer</value-type>
  9.         <heap unit="entries">10</heap>
  10.     </cache>
  11.     <!--定义缓存模板-->
  12.     <cache-template name="myTemplate">
  13.         <expiry>
  14.             <ttl unit="seconds">60</ttl><!--缓存项的过期策略,60秒过期-->
  15.         </expiry>
  16.     </cache-template>
  17. </config>
复制代码
3.2.3 数据的持久化
Ehcache还可以将数据落地本地磁盘,如许的话,当服务重启后,依然会从磁盘反序列化数据到内存中,实现数据的持久化代码如下:
  1. @Test
  2. public void test1() {
  3.     // 声明存储位置
  4.     String path = "D:\\ehcache";
  5.     // 初始化 CacheManager
  6.     CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
  7.             // 设置存储位置
  8.             .with(CacheManagerBuilder.persistence(path))
  9.             // 一个CacheManager可以管理多个Cache
  10.             .withCache("ehcacheDemo",
  11.                     CacheConfigurationBuilder.newCacheConfigurationBuilder(
  12.                             String.class,
  13.                             String.class,
  14.                             // heap相当于设置数据在堆内存中存储的 个数 或者 大小
  15.                             ResourcePoolsBuilder.newResourcePoolsBuilder()
  16.                                     // 堆内内存
  17.                                     .heap(10, MemoryUnit.MB)
  18.                                     // 堆外内存
  19.                                     // off-heap大小必须 大于 heap 设置的内存大小
  20.                                     .offheap(15,MemoryUnit.MB)
  21.                                     // 磁盘存储,记得添加true,才能正常持久化,并且序列号以及反序列化
  22.                                     // disk大小必须 大于 off-heap 设置的内存
  23.                                     .disk(20,MemoryUnit.MB,true)).build())
  24.             .build(true);
  25.     // 如果 CacheManagerBuilder.build(); 如果没有传参数,需要手动调用init()
  26.     // cacheManager.init();
  27.     // 基于 CacheManager 获取 Cache对象
  28.     Cache<String, String> ehCache = cacheManager.getCache("ehcacheDemo", String.class, String.class);
  29.     // 放去缓存
  30.     ehCache.put("ehcache", "hello ehcache");
  31.     // 取
  32.     System.out.println(ehCache.get("ehcache"));
  33.     // 保证数据正常持久化不丢失,记得 close()
  34.     cacheManager.close();
  35. }
复制代码
3.2.4 总结
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点。EhCache支持单机缓存和分布式缓存,分布式可以理解为缓存数据的共享,这就导致内存缓存数据量偏小。ehcache缓存非常存储和读取非常快。

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

3.3.2 Caffeine的简单利用

  • 缓存加载计谋

  • Cache手动创建
最普通的一种缓存,无需指定加载方式,必要手动调用put()进行加载。必要留意的是put()方法对于已存在的key将进行覆盖,这点和Map的表现是一致的。在获取缓存值时,如果想要在缓存值不存在时,原子地将值写入缓存,则可以调用get(key, k -> value)方法,该方法将制止写入竞争。调用invalidate()方法,将手动移除缓存。
在多线程情况下,当利用get(key, k -> value)时,如果有另一个线程同时调用本方法进行竞争,则后一线程会被阻塞,直到前一线程更新缓存完成;而若另一线程调用getIfPresent()方法,则会立即返回null,不会被阻塞。
  1.  @Test
  2.     public void test1() {
  3.         Cache<Object, Object> cache = Caffeine.newBuilder()
  4.                 //初始数量
  5.                 .initialCapacity(10)
  6.                 //最大条数
  7.                 .maximumSize(10)
  8.                 //expireAfterWrite和expireAfterAccess同时存在时,以expireAfterWrite为准
  9.                 //最后一次写操作后经过指定时间过期
  10.                 .expireAfterWrite(1, TimeUnit.SECONDS)
  11.                 //最后一次读或写操作后经过指定时间过期
  12.                 .expireAfterAccess(1, TimeUnit.SECONDS)
  13.                 //监听缓存被移除
  14.                 .removalListener((key, val, removalCause) -> { })
  15.                 //记录命中
  16.                 .recordStats()
  17.                 .build();
  18.         cache.put("1","张三");
  19.         //张三
  20.         System.out.println(cache.getIfPresent("1"));
  21.         //存储的是默认值
  22.         System.out.println(cache.get("2",o -> "默认值"));
  23. }
复制代码

  • Loading Cache主动创建
LoadingCache是一种主动加载的缓存。其和普通缓存不同的地方在于,当缓存不存在/缓存已逾期时,若调用get()方法,则会主动调用CacheLoader.load()方法加载最新值。调用getAll()方法将遍历全部的key调用get(),除非实现了CacheLoader.loadAll()方法。利用LoadingCache时,必要指定CacheLoader,并实现此中的load()方法供缓存缺失时主动加载。
在多线程情况下,当两个线程同时调用get(),则后一线程将被阻塞,直至前一线程更新缓存完成。
   
  1.  //Loading Cache自动创建
  2.     @Test
  3.     public void test2() {
  4.         LoadingCache<String, String> loadingCache = Caffeine.newBuilder()
  5.                 //创建缓存或者最近一次更新缓存后经过指定时间间隔,刷新缓存;refreshAfterWrite仅支持LoadingCache
  6.                 .refreshAfterWrite(10, TimeUnit.SECONDS)
  7.                 .expireAfterWrite(10, TimeUnit.SECONDS)
  8.                 .expireAfterAccess(10, TimeUnit.SECONDS)
  9.                 .maximumSize(10)
  10.                 //根据key查询数据库里面的值,这里是个lamba表达式
  11.                 .build(key -> new Date().toString());
  12.         loadingCache.put("1","张三");
  13.         //张三
  14.         System.out.println(loadingCache.getIfPresent("1"));
  15.         //存储的是默认值
  16.         System.out.println(loadingCache.get("2",o -> "默认值"));
  17. }
复制代码

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

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

  1.  //Async Cache异步获取
  2.     @Test
  3.     public void test3() {
  4.         AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
  5.                 .refreshAfterWrite(1, TimeUnit.SECONDS)
  6.                 .expireAfterWrite(1, TimeUnit.SECONDS)
  7.                 .expireAfterAccess(1, TimeUnit.SECONDS)
  8.                 .maximumSize(10)
  9.                 .buildAsync(key -> {
  10.                     try {
  11.                         // 模拟数据库查询延迟
  12.                         Thread.sleep(1000);
  13.                     } catch (InterruptedException e) {
  14.                         Thread.currentThread().interrupt();
  15.                     }
  16.                     // 模拟从数据库获取的数据
  17.                     return new Date().toString();
  18.                 });
  19.         // 获取缓存中的值
  20.         CompletableFuture<String> future = asyncLoadingCache.get("1");
  21.         // 当获取完成时,打印结果
  22.         future.thenAccept(System.out::println);
  23.         // 等待一段时间,确保异步加载完成
  24.         try {
  25.             Thread.sleep(2000);
  26.         } catch (InterruptedException e) {
  27.             e.printStackTrace();
  28.         }
  29.     }
复制代码


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

  • 基于容量的驱逐(LRU)
基于容量的驱逐是指缓存在到达一定的容量后,会按照最近最少利用(Least Recently Used)的计谋主动淘汰掉一些缓存项。这通常用于限定缓存占用的内存空间。
 
  1. //基于容量驱逐
  2.     @Test
  3.     public void maximumSizeTest() throws InterruptedException {
  4.         Cache<Integer, Integer> cache = Caffeine.newBuilder()
  5.                 //超过10个后会使用W-TinyLFU算法进行淘汰
  6.                 .maximumSize(10)
  7.                 .evictionListener((key, val, removalCause) -> {
  8.                     System.out.println("淘汰缓存:key:" + key + " val:" + val);
  9.                 })
  10.                 .build();
  11.         for (int i = 1; i < 20; i++) {
  12.             cache.put(i, i);
  13.         }
  14.         Thread.sleep(500);//缓存淘汰是异步的
  15.         // 打印还没被淘汰的缓存
  16.         System.out.println(cache.asMap());
  17. }
复制代码

  • 基于时间的驱逐
基于时间的驱逐是指缓存项在一定时间后主动被淘汰。可以基于末了一次写入时间或者末了一次访问时间来淘汰缓存项。
  1.     /**
  2.      * 访问后到期(每次访问都会重置时间,也就是说如果一直被访问就不会被淘汰)
  3.      */
  4.     @Test
  5.     public void expireAfterAccessTest() throws InterruptedException {
  6.         Cache<Integer, Integer> cache = Caffeine.newBuilder()
  7.                 .expireAfterAccess(1, TimeUnit.SECONDS)
  8.                 //可以指定调度程序来及时删除过期缓存项,而不是等待Caffeine触发定期维护
  9.                 //若不设置scheduler,则缓存会在下一次调用get的时候才会被动删除
  10.                 .scheduler(Scheduler.systemScheduler())
  11.                 .evictionListener((key, val, removalCause) -> {
  12.                     log.info("淘汰缓存:key:{} val:{}", key, val);
  13.                 })
  14.                 .build();
  15.         cache.put(1, 2);
  16.         System.out.println(cache.getIfPresent(1));
  17.         Thread.sleep(3000);
  18.         System.out.println(cache.getIfPresent(1));//null
复制代码

  • 革新机制
Caffeine 缓存库提供了灵活的革新机制,可以在缓存项即将逾期时主动革新数据,以确保缓存数据的时效性。refreshAfterWrite()表示x秒后主动革新缓存的计谋可以配合淘汰计谋利用,留意的是革新机制只支持LoadingCache和AsyncLoadingCache。
  1. //刷新机制
  2.     private static int NUM = 0;
  3.     @Test
  4.     public void refreshAfterWriteTest() throws InterruptedException {
  5.         LoadingCache<Integer, Integer> cache = Caffeine.newBuilder()
  6.                 .refreshAfterWrite(1, TimeUnit.SECONDS)
  7.                 //模拟获取数据,每次获取就自增1
  8.                 .build(integer -> ++NUM);
  9.         //获取ID=1的值,由于缓存里还没有,所以会自动放入缓存
  10.         System.out.println(cache.get(1));// 1
  11.         // 延迟2秒后,理论上自动刷新缓存后取到的值是2
  12.         // 但其实不是,值还是1,因为refreshAfterWrite并不是设置了n秒后重新获取就会自动刷新
  13.         // 而是x秒后&&第二次调用getIfPresent的时候才会被动刷新
  14.         Thread.sleep(2000);
  15.         System.out.println(cache.getIfPresent(1));// 1
  16.         //此时才会刷新缓存,而第一次拿到的还是旧值
  17.         System.out.println(cache.getIfPresent(1));// 2
  18. }
复制代码

  • 统计
Caffeine 缓存库提供了内置的统计功能,可以资助开发者监控和调优缓存性能。通过启用统计功能,你可以网络关于缓存操纵的详细信息,例如命中率、未命中率、加载次数、加载时间等。
 
  1.  //统计
  2.     @Test
  3.     public void requestCount(){
  4.         LoadingCache<String, String> cache = Caffeine.newBuilder()
  5.                 //创建缓存或者最近一次更新缓存后经过指定时间间隔,刷新缓存;refreshAfterWrite仅支持LoadingCache
  6.                 .refreshAfterWrite(1, TimeUnit.SECONDS)
  7.                 .expireAfterWrite(1, TimeUnit.SECONDS)
  8.                 .expireAfterAccess(1, TimeUnit.SECONDS)
  9.                 .maximumSize(10)
  10.                 //开启记录缓存命中率等信息
  11.                 .recordStats()
  12.                 //根据key查询数据库里面的值
  13.                 .build(key -> {
  14.                     Thread.sleep(1000);
  15.                     return new Date().toString();
  16.                 });
  17.         cache.put("1", "shawn");
  18.         cache.get("1");
  19.         /*
  20.          * hitCount :命中的次数
  21.          * missCount:未命中次数
  22.          * requestCount:请求次数
  23.          * hitRate:命中率
  24.          * missRate:丢失率
  25.          * loadSuccessCount:成功加载新值的次数
  26.          * loadExceptionCount:失败加载新值的次数
  27.          * totalLoadCount:总条数
  28.          * loadExceptionRate:失败加载新值的比率
  29.          * totalLoadTime:全部加载时间
  30.          * evictionCount:丢失的条数
  31.          */
  32.         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还内置了统计监控功能,资助开发者优化缓存性能。报告通过介绍这些技能和框架,为读者提供了理论与实践相结合的缓存解决方案,以优化体系性能。


















免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

温锦文欧普厨电及净水器总代理

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表