《后端程序猿 · Caffeine 本地缓存》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻一周,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,如需交流,欢迎留言评论。👍

文章目录

    • 写在前面的话
    • 技术统括
      • 技术简介
      • 选型比较
    • 实战运用
      • 快速入门
      • Bean和Util
      • SpringCache 模式
    • 技术拓展
      • 配置属性
      • 清除/驱逐策略
      • 过期/更新策略
      • 填充策略
      • 移除监听
      • 写入/删除监听
      • 统计信息
    • 总结陈词

写在前面的话

笔者所在公司的框架采用 Redis 作为缓存中间件,在部分场景下,可以借用 Redis 实现增强接口性能、减轻数据库压力、充当持久存储等功能。 但程序访问 Redis 毕竟需要消耗网络带宽,此外,经常由于各种因素导致 Redis 的性能降低,诸如编码不当、键过多、 网络异常等。 鉴于此,公司框架基于 Google 开发的高性能的 Java 缓存库 Caffeine,封装了本地缓存工具,便于业务项目使用。由于目前 Redis 已广泛使用,框架层面并未将本地缓存与 @Cacheable 等注解绑定,而是基于按需使用的原则,以注入 Bean 的形式封装工具方法


技术统括

技术简介

【Caffeine 技术简介】
Caffeine 是一个高性能的 Java 本地缓存库,提供了强大的缓存功能和灵活的配置选项,你可以使用 Caffeine 来实现本地缓存,并根据具体的需求进行配置和使用。
Caffeine 是基于 Java8 的高性能本地缓存库,并且在 Spring5 (SpringBoot 2.x) 后,Spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。
Caffeine 是在 Guava Cache 的基础上做一层封装,性能有明显提高,二者同属于内存级本地缓存,从并发的角度来讲,Caffeine明显优于Guava,原因是使用了Java 8最新的StampedLock锁技术。

据说,比 Guava Cache 优秀,那既然 Guava 还没开始用,那就直接它吧。
Maven依赖都不需要单独引入,SB2.x自动引入了,爽。

【Caffeine 优势特性】
Caffeine提供灵活的结构来创建缓存,并且有以下特性:
自动加载条目到缓存中,可选异步方式
可以基于大小剔除
可以设置过期时间,时间可以从上次访问或上次写入开始计算
异步刷新
keys自动包装在弱引用中
values自动包装在弱引用或软引用中
条目剔除通知
缓存访问统计

【Caffeine 使用场景】
Caffeine 是一个高性能的 Java 本地缓存库,适用于各种日常开发场景。
以下是一些 Caffeine 在日常开发中适合做的事情:
缓存常用数据:使用 Caffeine 缓存常用的数据,例如配置信息、用户信息、系统参数等,可以提高数据的访问速度和系统的性能。
减轻数据库压力:将频繁访问的数据库查询结果缓存到 Caffeine 中,可以减轻数据库的压力,提高系统的并发处理能力。
缓存计算结果:使用 Caffeine 缓存计算结果,例如复杂查询结果、数据聚合结果等,可以避免重复计算,提高系统的响应速度。
实现数据预热:在系统启动时将一些常用的数据预先加载到 Caffeine 缓存中,可以提高系统的初始化速度和响应速度。
实现请求限流:使用 Caffeine 缓存来记录请求次数和频率,实现请求的限流和流量控制,保护系统的稳定性和可用性。
实现本地锁:利用 Caffeine 缓存的原子性操作特性,可以实现分布式锁的简单版本,用于控制并发访问。
缓存控制器结果:在 Spring MVC 或 Spring Boot 应用中,可以使用 Caffeine 缓存控制器方法的返回结果,减少方法的执行次数,提高系统的性能和吞吐量。
总的来说,Caffeine 是一个功能强大、性能优越的本地缓存库,适用于各种日常开发场景,可以提高系统的性能、稳定性和可维护性。

【 补充:Guava LoadingCache 适合存储那些满足以下条件的数据】
频繁访问的数据:LoadingCache 提供了高性能的数据读取和写入,适合缓存那些被频繁访问的数据。这些数据可能是热点数据,经常被应用程序读取,但不经常更新。
计算密集型或者昂贵的数据:LoadingCache 可以在缓存中存储一些计算密集型或者昂贵的数据,例如数据库查询结果、API 调用结果等。这样可以避免重复计算或者昂贵的网络请求,提高系统的性能和响应速度。
临时性的数据:LoadingCache 也适合存储一些临时性的数据,例如会话数据、用户权限信息等。这些数据可能在一段时间内频繁被访问,但是不需要长期保存。
不需要持久化的数据:LoadingCache 是一个本地缓存,不具备持久化存储的能力。因此适合存储一些不需要长期保存的数据,例如缓存数据源的数据、临时计算结果等。
需要自动加载和刷新的数据:LoadingCache 支持自动加载和刷新数据,可以通过设置 refreshAfterWrite 来定期刷新缓存数据,以保持数据的新鲜性。因此适合存储那些需要定期刷新的数据,例如缓存数据源的数据、动态配置信息等。
总的来说,LoadingCache 适合存储那些被频繁访问、不需要持久化存储、临时性的数据,以及那些需要自动加载和刷新的数据。通过合理使用 LoadingCache,可以提高系统的性能、减少资源消耗,同时提供更好的用户体验。


选型比较

【Caffeine 和 GuavaCache 差异】
剔除算法方面,GuavaCache采用的是「LRU」算法,而Caffeine采用的是「Window TinyLFU」算法,这是两者之间最大,也是根本的区别。
立即失效方面,Guava会把立即失效 (例如:expireAfterAccess(0) and expireAfterWrite(0)) 转成设置最大Size为0。这就会导致剔除提醒的原因是SIZE而不是EXPIRED。Caffiene能正确识别这种剔除原因。
取代提醒方面,Guava只要数据被替换,不管什么原因,都会触发剔除监听器。而Caffiene在取代值和先前值的引用完全一样时不会触发监听器。
异步化方方面,Caffiene的很多工作都是交给线程池去做的(默认:ForkJoinPool.commonPool()),例如:剔除监听器,刷新机制,维护工作等。

【Caffeine 和 Redis 区别】
本地缓存与分布式缓存对应,缓存进程和应用进程同属于一个JVM,数据的读、写在一个进程内完成。本地缓存没有网络开销,访问速度很快。
从横向对常用的缓存进行对比,有助于加深对缓存的理解,有助于提高技术选型的合理性。下面对比三种常用缓存:Redis、EhCache、Caffeine。
image.png

通常采用 Caffeine/Guava + Redis 实现二级缓存方案,先从本地拿,拿不到再从缓存获取,减少 Redis 的连接消耗。

【Caffeine 有什么用,为什么不直接用Map】
**解答1:**Caffeine 使用了 ConcurrentHashMap 作为其缓存数据结构的基础,但对其进行了一些优化和改进,以提高并发性能、减少内存消耗,并添加了一些额外的功能和特性,使其更适合于高性能的缓存应用场景。
ConcurrentHashMap 是 Java 标准库中提供的线程安全的哈希表实现,它使用了一种分段锁的方式来实现并发访问控制,以提高并发读写性能。Caffeine 利用了 ConcurrentHashMap 的并发性能和线程安全性,并在此基础上进行了优化和改进,以提供更高性能的缓存服务。
总的来说,尽管 Caffeine 的底层实现基于 ConcurrentHashMap,但它对 ConcurrentHashMap 进行了一些改进和扩展,使得它更适合于高性能、低延迟的缓存应用场景。
**解答2:**Caffeine 是一个用于构建内存缓存的 Java 库,它提供了一些高效、可配置的缓存功能,可以帮助开发人员在应用程序中轻松地实现缓存机制。
与直接使用 Java 中的 Map 不同,Caffeine 提供了更多的特性和优势,使得它在某些场景下更为适用:
自动加载和刷新机制:Caffeine 支持自动加载和刷新缓存中的条目,无需手动编写加载逻辑。通过 LoadingCache 接口,可以在缓存中不存在指定键的条目时,自动调用加载逻辑来获取新的值,并将其放入缓存中。
缓存的自动清理和过期处理:Caffeine 提供了可配置的过期策略,可以根据时间、大小或其他条件来自动清理缓存中的条目。这样可以确保缓存不会占用过多的内存,并及时清理过期的条目,保持缓存的有效性和性能。
高性能和低内存占用:Caffeine 的实现经过优化,具有很高的性能和低的内存占用。它使用了一些高效的数据结构和算法,以及基于并发的设计模式,可以在多线程环境下高效地处理并发访问和更新操作。
可扩展性和灵活性:Caffeine 提供了丰富的配置选项和扩展点,可以根据具体的需求和场景来定制缓存的行为。开发人员可以灵活地配置缓存的大小、过期时间、刷新策略等参数,以满足不同应用场景的需求。
总的来说,尽管 Java 中的 Map 提供了基本的键值对存储功能,但在需要更多高级特性和性能优化的场景下,使用 Caffeine 可能会更加合适和方便。Caffeine 提供了更丰富的功能和更高效的实现,可以帮助开发人员构建出更可靠、更高性能的缓存系统。


实战运用

快速入门

Step1、添加Maven依赖

注意,高版本Spring或SB以及依赖了caffeine,直接使用提供的版本即可,不要再额外引入了。

<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.1.8</version>
</dependency>

Step2、编写工具Bean

@Component
public class CaffeineCache {private final Cache<String, Object> cache;public CaffeineCache() {// 创建一个基于 Caffeine 的本地缓存,设置最大缓存条目数为 10000,过期时间为 10 分钟cache = Caffeine.newBuilder().maximumSize(10000).expireAfterWrite(10, TimeUnit.MINUTES).build();}// 添加缓存项public void put(String key, Object value) {cache.put(key, value);}// 获取缓存项public Object get(String key) {return cache.getIfPresent(key);}// 移除缓存项public void remove(String key) {cache.invalidate(key);}// 清空缓存public void clear() {cache.invalidateAll();}
}

Step3、使用测试

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class MyService {@Autowiredprivate CaffeineCache caffeineCache;public void doSomething() {// 添加缓存项caffeineCache.put("key", "value");// 获取缓存项Object value = caffeineCache.get("key");// 移除缓存项caffeineCache.remove("key");// 清空缓存caffeineCache.clear();}
}

通过以上步骤,你就可以在 Spring Boot 应用中使用 Caffeine 工具类来创建本地缓存,并在需要时进行缓存操作。你可以根据具体的需求调整缓存的配置参数,例如最大缓存条目数、过期时间等。

Bean和Util

将 Caffeine 缓存工具类设计为 Bean 是比较常见的做法,这样可以更好地与 Spring Boot 集成,并通过依赖注入的方式在需要的地方直接使用,同时也方便在配置类中对其进行配置和管理。
将 Caffeine 缓存工具类设计为 Bean 的优势包括:
便于管理和配置:作为 Spring Bean,可以利用 Spring 的依赖注入和配置功能,更方便地管理和配置 Caffeine 缓存的属性,如最大缓存条目数、过期时间等。
与 Spring Boot 集成更紧密:作为 Spring Bean,与 Spring Boot 的集成更加紧密,可以直接在其他 Bean 中通过自动装配进行使用,而不需要额外的配置。
易于测试:将 Caffeine 缓存工具类设计为 Bean 后,可以更方便地在单元测试中进行模拟和替换,提高测试的可维护性和灵活性。
因此,建议将 Caffeine 缓存工具类设计为 Spring Bean,以便更好地利用 Spring Boot 的特性和功能,并方便在应用程序中使用和管理。


SpringCache 模式

与SB整合通常体现在@Cacheable,有需要再扩展。
公司框架Redis使用已久,为减少影响,还是封装工具Bean,按需使用。


技术拓展

配置属性

initialCapacity 初始的缓存空间大小
maximumSize 缓存的最大条数
maximumWeight 缓存的最大权重
expireAfterAccess 最后一次写入或访问后,经过固定时间过期
expireAfterWrite 最后一次写入后,经过固定时间过期
refreshAfterWrite 写入后,经过固定时间过期,下次访问返回旧值并触发刷新
weakKeys 打开 key 的弱引用
weakValues 打开 value 的弱引用
softValues 打开 value 的软引用
recordStats 缓存使用统计
expireAfterWrite 和 expireAfterAccess 同时存在时,以 expireAfterWrite 为准。
weakValues 和 softValues 不可以同时使用。
maximumSize 和 maximumWeight 不可以同时使用。

清除/驱逐策略

缓存的驱逐策略是为了预测哪些数据在短期内最可能被再次用到,从而提升缓存的命中率。LRU策略或许是最流行的驱逐策略。但LRU通过历史数据来预测未来是局限的,它会认为最后到来的数据是最可能被再次访问的,从而给予它最高的优先级。
Caffeine提供三类驱逐策略:基于大小(size-based),基于时间(time-based)和基于引用(reference-based)

1、基于大小(size-based)
基于大小驱逐,有两种方式:一种是基于缓存大小,一种是基于权重。

// 根据缓存的计数进行驱逐
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder().maximumSize(10_000).build(key -> createExpensiveGraph(key));// 根据缓存的权重来进行驱逐(权重只是用于确定缓存大小,不会用于决定该缓存是否被驱逐)
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder().maximumWeight(10_000).weigher((Key key, Graph graph) -> graph.vertices().size()).build(key -> createExpensiveGraph(key));

2、基于时间:设置缓存的有效时间

// 设置缓存有效期为 10 秒,从最后一次写入开始计时 
Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(10)) .build();

3、基于引用:设置缓存为软引用或弱引用,利用GC来回收缓存数据。

// 性能较差,不建议使用。
Cache<String, String> cache = Caffeine.newBuilder().weakKeys().weakValues().build();

【弱引用相关补充】

Caffeine.weakKeys() 使用弱引用存储key。如果没有强引用这个key,则GC时允许回收该条目
Caffeine.weakValues() 使用弱引用存储value。如果没有强引用这个value,则GC时允许回收该条目
Caffeine.softValues() 使用软引用存储value, 如果没有强引用这个value,则GC内存不足时允许回收该条目

image.png


过期/更新策略

# expireAfterAccess:设置条目在最后一次访问后的过期时间。默认值为不过期。
# expireAfterWrite:设置条目在被创建或最后一次写入后的过期时间。默认值为不过期。
# refreshAfterWrite:这个其实算更新策略,设置条目在被创建或最后一次写入后的自动刷新时间。默认值为不自动刷新。
# expireAfter:
# 在expireAfter中需要自己实现Expiry接口,这个接口支持create,update,access了之后多久过期,
# 这里和前面两个API不同的是,需要你告诉缓存框架,他应该在具体的某个时间过期
# 也就是通过前面的重写create,update,access的方法,获取具体的过期时间。
Cache<String, String> cacheHandle = Caffeine.newBuilder().expireAfter(new Expiry<String, String>() {// 创建后多久过期@Overridepublic long expireAfterCreate(@NonNull String key, @NonNull String value, long currentTime) {return TimeUnit.SECONDS.toNanos(3); //3秒后过期}// 更新后多久过期@Overridepublic long expireAfterUpdate(@NonNull String key, @NonNull String value, long currentTime, @NonNegative long currentDuration) {return currentDuration; // 保持不变,即不改变过期时间}// 读取后多久过期@Overridepublic long expireAfterRead(@NonNull String key, @NonNull String value, long currentTime, @NonNegative long currentDuration) {return currentDuration; // 保持不变,即不改变过期时间}}).build();
cacheHandle.put("abc", "123");
System.out.println("abc的值:" + cacheHandle.getIfPresent("abc"));
ThreadUtil.sleep(5000);
System.out.println("abc的值:" + cacheHandle.getIfPresent("abc"));

填充策略

Caffeine 提供了四种缓存添加策略:手动加载,自动加载,手动异步加载和自动异步加载。
很好理解,其实就是build的几个重载模式。
参考:Caffeine Cache 进程缓存利器


移除监听

RemovalListener:如果我们需要在缓存被移除的时候,得到通知产生回调,并做一些额外处理工作。

Cache<String, String> cache = Caffeine.newBuilder().maximumSize(2).removalListener(((key, value, cause) -> {System.out.println("Removed key: " + key + ", value: " + value + ", cause: " + cause);})).build();
cache.put("key1", "value1");
cache.put("key2", "value22");
cache.put("key3", "value333");
ThreadUtil.sleep(1000);
System.out.println(cache.asMap());//下方是输出信息:
Removed key: key1, value: value1, cause: SIZE
{key2=value22, key3=value333}

写入/删除监听

@Autowired
private OnelinkCaffeineCacheHandle caffeineCache;Caffeine<Object, Object> customBuild = caffeineCache.getCustomBuild();
customBuild.writer(new CacheWriter<String, String>() {@Overridepublic void write(String key, String value) {System.out.println("Cache entry written for key: " + key + ", value: " + value);}@Overridepublic void delete(String key, String value, RemovalCause cause) {System.out.println("Cache entry removed for key: " + key + ", value: " + value + ", removal cause: " + cause);}
});

统计信息

【关于 CacheStats】
Guava 的 CacheStats 类是用来表示缓存的统计信息的。它提供了一组方法来获取缓存的命中率、加载次数、加载失败次数等信息。通过这些统计信息,可以帮助你了解缓存的使用情况,优化缓存的配置和性能。
以下是 CacheStats 类的一些常用方法:
hitCount():返回缓存命中的次数。
missCount():返回缓存未命中的次数。
loadSuccessCount():返回缓存加载成功的次数。
loadExceptionCount():返回缓存加载失败的次数。
totalLoadTime():返回缓存加载的总时间,单位为纳秒。
evictionCount():返回缓存中条目被回收的次数。
使用 CacheStats 类可以帮助你监控缓存的性能,并且根据统计信息来调整缓存的配置,以提高系统的性能和稳定性。

【示例代码】

Tips:for循环中大量使用才有统计的意义,正常生产环境也没必要记录。

public static void main(String[] args) {Cache<String, String> cache = Caffeine.newBuilder().maximumSize(2).recordStats().removalListener(((key, value, cause) -> {System.out.println("Removed key: " + key + ", value: " + value + ", cause: " + cause);})).build();// 添加一些条目cache.put("key1", "value1");cache.put("key2", "value22");cache.put("key3", "value333");ThreadUtil.sleep(1000);// 此时缓存大小超过最大权重,将会驱逐一些条目System.out.println(cache.asMap());System.out.println(cache.stats());//输出信息如下:// Removed key: key1, value: value1, cause: SIZE// {key2=value22, key3=value333}// CacheStats{hitCount=0, missCount=0, loadSuccessCount=0, loadFailureCount=0, totalLoadTime=0, evictionCount=1, evictionWeight=1}// hitCount(): 返回命中缓存的总数// evictionCount():缓存逐出的数量
}

总结陈词

上文介绍了本地缓存的用法,仅供参考。
本地缓存具备其独有美丽,可以搭配Redis发挥更多作用。
但切记缓存都是一个双刃剑,用的姿势如果不对,会造成更严重的后果。

💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

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

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

相关文章

EE架构大跃进:特斯拉、小鹏引领舱驾融合,从域控融合走向单SoC

作者 |肖恩 编辑 |德新 智能汽车发展到今天&#xff0c;整车电气架构已经从分布式架构逐渐迈向中央集成式架构&#xff0c;传统的小控制器被集成到按功能划分的大域控里&#xff0c;下一个阶段将是跨域的融合&#xff0c;通过不同功能域的集成实现中央计算平台的最终目标。 …

Visual Studio 中的键盘快捷方式

1. Visual Studio 中的键盘快捷方式 1.1. 可打印快捷方式备忘单 1.2. Visual Studio 的常用键盘快捷方式 本部分中的所有快捷方式都将全局应用&#xff08;除非另有指定&#xff09;。 “全局”上下文表示该快捷方式适用于 Visual Studio 中的任何工具窗口。 生成&#xff1…

[leetcode hot 150]第四百五十二题,用最少数量的箭引爆气球

题目&#xff1a; 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。…

[leetcode hot 150]第三题,无重复字符的最长子串

题目&#xff1a; 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长 子串的长度。 可以使用"滑动窗口"的方法来解决这个问题。基本思路如下: 使用两个指针(start和end)来定义一个窗口移动end指针来扩大窗口,直到遇到重复字符如果遇到重复字符,移动s…

Vite: 插件流水线之核心编译能力

概述 Vite 在开发阶段实现了一个按需加载的服务器&#xff0c;每一个文件请求进来都会经历一系列的编译流程&#xff0c;然后 Vite 会将编译结果响应给浏览器。在生产环境下&#xff0c;Vite 同样会执行一系列编译过程&#xff0c;将编译结果交给 Rollup 进行模块打包这一系列…

什么是 URL ?

统一资源定位符&#xff08;URL&#xff09;是一个字符串&#xff0c;它指定了一个资源在互联网上的位置以及如何访问它。URL 是由几部分组成的&#xff0c;每部分都有其特定的作用&#xff1a; 协议/方案&#xff1a;这是 URL 的开头部分&#xff0c;表明了用于访问资源的协议…

antfu/ni 在 Windows 下的安装

问题 全局安装 ni 之后&#xff0c;第一次使用会有这个问题 解决 在 powershell 中输入 Remove-Item Alias:ni -Force -ErrorAction Ignore之后再次运行 ni Windows 11 下的 Powershell 环境配置 可以参考 https://github.com/antfu-collective/ni?tabreadme-ov-file#how …

Java---Mybatis详解二

雄鹰展翅凌空飞&#xff0c; 大江奔流不回头。 壮志未酬心未老&#xff0c; 豪情万丈任遨游。 巍巍高山攀顶峰&#xff0c; 滔滔黄河入海流。 风云变幻凭君舞&#xff0c; 踏遍天涯尽逍遥。 目录 一&#xff0c;环境准备 二&#xff0c;删除 三&#xff0c;删除(预编译SQL) 为什…

Celery入门教程

一.Celery介绍 1.Celery架构 Celery架构基于可插拔组件&#xff08;pluggable components&#xff09;和根据选择的消息传输&#xff08;代理&#xff09;(message transport(broker))协议实现的消息交换机制。 2.Celery模块 &#xff08;1&#xff09;任务模块 Task 包含异…

2024中国西安科博会暨硬科技产业博览会11月召开

2024第18届中国西安国际科学技术产业博览会暨硬科技产业博览会 时间&#xff1a;2024年11月3日-5日 地点&#xff1a;西安国际会展中心 主办单位&#xff1a;中国国际科学技术合作协会 陕西省科技资源统筹中心 协办单位&#xff1a;西安市科学技术协会 西安市中小企业协会、…

昇思25天学习打卡营第3天|yulang

今天主要学习03-张量Tensor&#xff0c;主要包含了处理创建张量、张量的属性、张量索引和张量运算&#xff0c;稀疏张量&#xff0c;有点看不太懂&#xff0c;感觉要开始入门到放弃了&#xff1f;张量在构建和训练深度学习模型中的实际应用&#xff0c;如卷积神经网络。 张量&a…

Django学习第三天

python manage.py runserver 使用以上的命令启动项目 实现新建用户数据功能 views.py文件代码 from django.shortcuts import render, redirect from app01 import models# Create your views here. def depart_list(request):""" 部门列表 ""&qu…

一键获取:Win11笔记本系统下载地址!

在笔记本电脑操作中&#xff0c;用户想安装一款适合笔记本电脑使用的Win11系统&#xff0c;但不知道在哪里可以下载到&#xff1f;接下来系统之家小编给大家分享Win11笔记本系统下载地址&#xff0c;有需要的小伙伴一键点击即可获取&#xff0c;快速安装系统&#xff0c;即可体…

<电力行业> - 《第15课:电力领域(一)》

1 电网 发电厂与最终用电用户&#xff08;负荷&#xff09;往往相距很远&#xff0c;因此电力需要由电厂”输送“到最终用户&#xff0c;即“输电环节“&#xff0c;电流的输送往往导致因线路发热造成损耗&#xff0c;所以在输送的时候都是通过变电升高电压&#xff0c;让电流…

计算机网络 | 期末复习

物理层&#xff1a; 奈氏准则&#xff1a;带宽&#xff08;w Hz&#xff09;&#xff0c;在不考虑噪音的情况下&#xff0c;最大速率&#xff08;2W&#xff09;码元/秒 信噪比S/N&#xff1a;以分贝&#xff08;dB&#xff09;为度量单位。信噪比&#xff08;dB&#xff09;…

C++初学者指南-3.自定义类型(第一部分)-异常

C初学者指南-3.自定义类型(第一部分)-异常 文章目录 C初学者指南-3.自定义类型(第一部分)-异常简介什么是异常&#xff1f;第一个示例用途:报告违反规则的行为异常的替代方案标准库异常处理 问题和保证资源泄露使用 RAII 避免内存泄漏&#xff01;析构函数&#xff1a;不要让异…

SpringBoot源码阅读3-启动原理

SpringBootApplication public class DistApplication {public static void main(String[] args) {// 启动入口SpringApplication.run()SpringApplication.run(DistApplication.class, args);} }1、服务构建 这里"服务"指的是SpringApplication对象&#xff0c;服务…

2024年港澳台联考考生成绩数据分析来啦

分数线 出炉 2024年的港澳台联考正式出分&#xff01;根据考生成绩&#xff0c;全国联招划档线如下&#xff1a; 一、本科批次 &#xff08;一&#xff09;普通类院校&#xff08;专业&#xff09;&#xff1a;文史类365分、理工类390分&#xff08;部分院校执行高分线&#…

持续直击WCCI 2024:金耀初教授、台湾省台北分会等获殊荣 横滨夜景美不胜收

持续直击WCCI 2024&#xff1a;金耀初教授、台湾省台北分会等获殊荣&#xff01;横滨夜景美不胜收&#xff01; 会议之眼 快讯 会议介绍 IEEE WCCI&#xff08;World Congress on Computational Intelligence&#xff09;2024&#xff0c;即2024年IEEE世界计算智能大会&…

BAS(入侵与攻击模拟)正在替代红队测试?

之前经常会被用户问到&#xff0c;漏扫、渗透和红队红的区别是啥&#xff1f; 传统的漏扫、渗透和红蓝对抗&#xff0c;可以看到工具化的漏洞不可靠&#xff0c;人工的成本就高。怎么找到一个漏洞可信度又高&#xff0c;成本又低的&#xff0c;就诞生了BAS。 抛开漏扫&#xf…