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.mzph.cn/pingmian/57829.shtml

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

相关文章

表格编辑demo

<el-form :model"form" :rules"status ? rules : {}" ref"form" class"form-container" :inline"true"><el-table :data"tableData"><el-table-column label"计算公式"><templat…

ArcGIS001:ArcGIS10.2安装教程

摘要&#xff1a;本文详细介绍arcgis10.2的安装、破解、汉化过程。 一、软件下载 安装包链接&#xff1a;https://pan.baidu.com/s/1T3UJ7t_ELZ73TH2wGOcfpg?pwd08zk 提取码&#xff1a;08zk 二、安装NET Framework 3.5 双击打开控制面板&#xff0c;点击【卸载程序】&…

05方差分析续

文章目录 1.Three way ANOVA2.Latin square design2.Hierarchical (nested) ANOVA3.Split-plot ANOVA4.Repeated measures ANOVA5.Mixed effect models 1.Three way ANOVA 三因素相关分析 单因子分析的代码 data(mtcars) nrow(mtcars) # 32 mtcars$cyl as.factor(mtcars$cyl…

c#子控件拖动父控件方法及父控件限在窗体内拖动

一、效果 拖放位置不超过窗体四边,超出后自动靠边停靠支持多子控件拖动指定控件拖放(含父控件或窗体)点击左上角logo弹出消息窗口(默认位置右下角)1.1 效果展示 1.2 关于MQTTnet(最新版v4.3.7.1207)实现在线客服功能,见下篇博文 https://github.com/dotnet/MQTTnet 网上…

BIO,NIO,直接内存,零拷贝

前置知识 什么是Socket&#xff1f; Socket是应用层与TCP/IP协议族通信的中间软件抽象层&#xff0c;它是一组接口&#xff0c;一般由操作系统提供。在设计模式中&#xff0c;Socket其实就是一个门面模式&#xff0c;它把复杂的TCP/IP协议处理和通信缓存管理等等都隐藏在Sock…

莱维飞行(Levy Flight)机制的介绍和MATLAB例程

文章目录 莱维飞行机制算法简介自然现象中的应用优化问题中的应用关键公式 MATLAB代码示例代码说明运行结果 莱维飞行机制算法的应用前景1. 自然科学中的应用2. 计算机科学中的应用3. 工程技术中的应用4. 金融与经济学中的应用5. 医疗与生物信息学中的应用6. 未来研究方向 结论…

【软件工程】软件工程入门

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;软件开发必练内功_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前…

软件分享丨Marktext 编辑器

Marktext是一款开源免费的Markdown编辑器&#xff0c;它具有简洁优雅的界面设计和强大的功能&#xff0c;支持多种Markdown语法&#xff0c;包括表格、流程图、甘特图、数学公式、代码高亮等。Marktext还支持导出HTML和PDF格式的文档&#xff0c;非常适合需要编写Markdown文档的…

5G NR:BWP入门

简介 5G NR 系统带宽比4G LTE 大了很多&#xff0c;4G LTE 最大支持带宽为20MHz&#xff0c; 而5G NR 的FR1 最大支持带宽为100MHz&#xff0c; FR2 最大支持带宽为 400MHz。 带宽越大&#xff0c;意味了终端功耗越多。为了减少终端的功耗&#xff0c;5G NR 引入了BWP(Band Wid…

不写单元测试的我,被批了

最近在看单元测试的东西&#xff0c;想跟大家聊聊我的感受。单元测试这块说实在的&#xff0c;我并不太熟悉&#xff0c;我几乎不写单元测试&#xff0c;也不太爱写单元测试。 当我推广消息推送平台austin的时候&#xff0c;有过批评我整个项目没有单元测试&#xff0c;也有过…

《a16z : 2024 年加密货币现状报告》解析

加密社 原文链接&#xff1a;State of Crypto 2024 - a16z crypto译者&#xff1a;AI翻译官&#xff0c;校对&#xff1a;翻译小组 当我们两年前第一次发布年度加密状态报告的时候&#xff0c;情况跟现在很不一样。那时候&#xff0c;加密货币还没成为政策制定者关心的大事。 比…

生信软件39 - GATK最佳实践流程重构,提高17倍分析速度的LUSH流程

1. LUSH流程简介 基因组测序通常用于分子诊断、分期和预后&#xff0c;而大量测序数据在分析时间方面提出了挑战。 对于从FASTQ到VCF的整个流程&#xff0c;LUSH流程在非GVCF和GVCF模式下都大大降低了运行时间&#xff0c;30 X WGS数据耗时不到2 h&#xff0c;从BAM到VCF约需…

使用 ASP.NET Core 8.0 创建最小 API

构建最小 API&#xff0c;以创建具有最小依赖项的 HTTP API。 它们非常适合需要在 ASP.NET Core 中仅包括最少文件、功能和依赖项的微服务和应用。 本教程介绍使用 ASP.NET Core 生成最小 API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是使用控制器。 有关在最小 …

认识CSS语法

CSS&#xff08;网页美容&#xff09; 重点&#xff1a;选择器、盒子模型、浮动、定位、动画&#xff0c;伸缩布局 Css的作用&#xff1a; 美化网页&#xff1a;CSS控制标签的样式 网页布局&#xff1a;CSS控制标签的位置 概念&#xff1a;层叠样式表&#xff08;级联样式表…

Maven(解决思路)

1.前言 作为一名一线的开发人员&#xff0c;maven大概率是我们用的最多的依赖管理&#xff0c;但是你知道我们的maven出现问题后怎么去排查么&#xff1f;不对&#xff0c;确切的来说&#xff0c;假如你去导入的包没有被成功导入&#xff0c;你有什么方法去排查、去解决这个问题…

Linux-Centos操作系统备份及还原(整机镜像制作与还原)--再生龙

适用场景 Linux系统设备需要备份整机数据&#xff0c;或者需要还原到多台设备上。适用再生龙工具进行整机备用和还原。 镜像制作 下载再生龙镜像&#xff1a;clonezilla-live-2.6.4-10-amd64.iso&#xff0c;制作启动盘-设置U盘启动 启动后界面如下选择第四项other modes of…

力扣143:重排链表

给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进行节点交换。 示…

如何使用的是github提供的Azure OpenAI服务

使用的是github提供的Azure OpenAI的服务gpt-4o 说明&#xff1a;使用的是github提供的Azure OpenAI的服务&#xff0c;可以无限薅羊毛。开源地址 进入&#xff1a; 地址 进入后点击 右上角“Get API key”按钮 点击“Get developer key” 选择Beta版本“Generate new to…

HarmonyOS开发 - 本地持久化之实现LocalStorage实例

用户首选项为应用提供Key-Value键值型的数据处理能力&#xff0c;支持应用持久化轻量级数据&#xff0c;并对其修改和查询。数据存储形式为键值对&#xff0c;键的类型为字符串型&#xff0c;值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。 说明&#x…

C#通过异或(^)运算符制作二进制加密(C#实现加密)

快速了解异或运算符&#xff1a; 异或运算符在C#中用 “^” 来表示 口诀&#xff1a;相同取0&#xff0c;相异取1 简单加密解密winform示例&#xff1a; /// <summary>/// 异或运算符加密实现/// </summary>/// <param name"p_int_Num">初始值<…