深入理解缓存淘汰策略:LRU 与 LFU 算法详解及 Java 实现
一、LRU (Least Recently Used - 最近最少使用)
LRU 策略的核心思想是:当缓存空间不足时,优先淘汰最近最长时间未被访问的数据。它基于“时间局部性”原理,即最近被访问的数据,在未来被访问的概率也更高。
LeetCode 146. LRU 缓存机制
这道题要求我们设计并实现一个满足 LRU 约束的数据结构。
核心思路:哈希表 + 双向链表
为了同时满足快速查找(get 操作)和快速增删(维护访问顺序)的需求,我们采用“哈希表 + 双向链表”的组合:
-
HashMap<Integer, Node>: 哈希表用于存储键(Key)到链表节点(Node)的映射。这使得我们能够以 O(1) 的平均时间复杂度通过 Key 快速定位到链表中的节点。
-
双向链表 (DoubleList): 双向链表按照节点的访问顺序来组织。
- 最近使用的节点放在链表尾部。
- 最久未使用的节点放在链表头部。
- 当缓存容量满时,淘汰链表头部的节点。
- 当访问(get 或 put 更新)一个节点时,将其移动到链表尾部。
- 添加新节点时,也将其添加到链表尾部。
为什么是这个组合?
- 哈希表保证了 get 操作查找节点的时间复杂度为 O(1)。
- 双向链表保证了在链表头部删除(淘汰)、在链表尾部添加(新访问/新添加)、以及将任意节点移动到尾部(更新访问)的操作时间复杂度都为 O(1)。(普通链表无法 O(1) 删除任意指定节点)。
- HashMap 帮助我们快速找到链表中的节点,然后双向链表快速完成节点的移动或删除。
图示理解:
(此处可想象或引用你提供的图示 image-20240714103929-cde7wui.png 和 image-20240714103937-nq23qq9.png 来展示数据结构)
Java 实现 (LRUCache)
import java.util.HashMap;class LRUCache {// Key -> Node(key, val)private HashMap<Integer, Node> map;// 双向链表,存储 Nodeprivate DoubleList cache;// 最大容量private int cap;public LRUCache(int capacity) {this.cap = capacity;map = new HashMap<>();cache = new DoubleList();}/* 将某个 key 提升为最近使用的 */private void makeRecent(Node node) {// 先从链表中删除cache.remove(node);// 再添加到链表尾部cache.addLast(node);}/* 添加最近使用的元素 */private void addRecent(Node node) {// 添加到链表尾部cache.addLast(node);// 同时添加到 map 中map.put(node.key, node);}/* 删除某一个 key 对应的 Node */private void removeNode(Node node) {// 从链表中删除cache.remove(node);// 从 map 中删除map.remove(node.key);}/* 删除最久未使用的元素 (链表头部第一个节点) */private void removeLeastRecent() {// 从链表头部删除节点Node deletedNode = cache.removeFirst();// 如果链表不为空,则从 map 中也删除if (deletedNode != null) {map.remove(deletedNode.key);}}public int get(int key) {if (!map.containsKey(key)) {return -1; // 键不存在}// 键存在,将其变为最近使用Node node = map.get(key);makeRecent(node);return node.val;}public void put(int key, int value) {if (map.containsKey(key)) {// 如果 key 已存在,更新值并将节点移到末尾// 1. 从 map 中删除旧节点 (因为要更新节点,虽然key相同) - 或者直接更新node的val// Node oldNode = map.get(key);// removeNode(oldNode); // 更简单的做法是下面这样// 1. 更新节点值Node node = map.get(key);node.val = value;// 2. 将节点移到末尾makeRecent(node);// 注意:不能简单地 removeNow + addRecent,因为这会创建一个新 Node 对象// removeNow(map.get(key));// addrecent(new Node(key,value)); // 这样做逻辑上是更新,但效率低且可能引入问题return;}// 如果 key 不存在,需要添加新节点// 检查容量是否已满if (cache.size() == cap) {// 删除最久未使用的元素removeLeastRecent();}// 添加新节点到末尾addRecent(new Node(key, value));}// --- 内部类定义 ---class Node {public int key, val;public Node next, pre;public Node(int k, int v) {this.key = k;this.val = v;}}class DoubleList {// 虚拟头尾节点,简化边界处理private Node head, tail;// 链表元素数private int size;public DoubleList() {head = new Node(0, 0);tail = new Node(0, 0);head.next = tail;tail.pre = head;size = 0;}// 在链表尾部添加节点 x(表示最近使用)public void addLast(Node x) {x.pre = tail.pre;x.next = tail;tail.pre.next = x;tail.pre = x;size++;}// 删除链表中的 x 节点(x 一定存在)public void remove(Node x) {x.pre.next = x.next;x.next.pre = x.pre;size--;}// 删除链表中第一个节点(最久未使用),并返回该节点public Node removeFirst() {if (head.next == tail) { // 链表为空return null;}Node first = head.next;remove(first);return first;}// 返回链表长度public int size() {return size;}}
}
关键点总结 (LRU):
-
get 操作:通过 map 找到节点,调用 makeRecent 将其移到链表尾部。
-
put 操作:
- 若 Key 存在:更新节点 value,调用 makeRecent 将其移到链表尾部。
- 若 Key 不存在:检查容量,若满则调用 removeLeastRecent 淘汰链表头部节点(并从 map 移除);然后调用 addRecent 将新节点添加到链表尾部和 map 中。
二、LFU (Least Frequently Used - 最不经常使用)
LFU 策略的核心思想是:当缓存空间不足时,优先淘汰访问频次最低的数据。如果访问频次最低的数据有多条,则淘汰其中最旧(按访问时间算,即最早进入该最低频次)的数据。
LeetCode 460. LFU 缓存
这道题要求我们设计并实现一个满足 LFU 约束的数据结构,且 get 和 put 操作的时间复杂度都为 O(1)。
核心思路:哈希表组合 + LinkedHashSet
LFU 的 O(1) 实现比 LRU 更复杂,需要巧妙地组合多个哈希表:
-
HashMap<Integer, Integer> keyToVal: 存储 Key 到 Value 的映射,用于 O(1) 获取值。
-
HashMap<Integer, Integer> keyToFreq: 存储 Key 到其访问频次(Frequency)的映射,用于 O(1) 获取和更新 Key 的频次。
-
HashMap<Integer, LinkedHashSet<Integer>> freqToKeys: 存储频次(Frequency)到拥有该频次的 Key 集合的映射。
-
为什么是 LinkedHashSet?
- 我们需要一个集合来存储同一频次的所有 Key。
- 当某个 Key 的频次增加时,需要能 O(1) 地从旧频次的集合中删除该 Key。HashSet 提供 O(1) 的平均删除时间。
- 当频次最低的有多个 Key 时,需要淘汰最旧的 Key。LinkedHashSet 在保持 O(1) 增删查的同时,内部维护了元素的插入顺序。因此,当需要淘汰时,迭代 LinkedHashSet 的第一个元素即为该频次下最旧的 Key。
- 普通的 LinkedList 无法 O(1) 删除任意指定 Key,而 HashSet 不保证顺序。LinkedHashSet 是最佳选择。
-
-
int minFreq: 一个变量,记录当前缓存中存在的最低访问频次。这使得在需要淘汰时,能 O(1) 定位到最低频次的 Key 集合。
图示理解:
(此处可想象或引用你提供的图示 image-20240714113101-7ery7zh.png 和 image-20240714113113-1fnp3y7.png 来展示数据结构关系)
Java 实现 (LFUCache)
import java.util.HashMap;
import java.util.LinkedHashSet;class LFUCache {// key -> valueHashMap<Integer, Integer> keyToVal;// key -> frequencyHashMap<Integer, Integer> keyToFreq;// frequency -> keys (保持插入顺序,即时间顺序)HashMap<Integer, LinkedHashSet<Integer>> freqToKeys;// 记录当前缓存中存在的最小频次int minFreq;// 缓存的最大容量int cap;public LFUCache(int capacity) {keyToVal = new HashMap<>();keyToFreq = new HashMap<>();freqToKeys = new HashMap<>();this.cap = capacity;this.minFreq = 0; // 初始最小频次为0}public int get(int key) {if (!keyToVal.containsKey(key)) {return -1;}// 增加 key 对应的频次increaseFreq(key);return keyToVal.get(key);}public void put(int key, int value) {if (this.cap <= 0) { // 处理容量为0或负数的边界情况return;}if (keyToVal.containsKey(key)) {// key 已存在,更新 valuekeyToVal.put(key, value);// 增加 key 对应的频次increaseFreq(key);// 注意:LFU 的更新操作仅涉及更新值和增加频率,不需要像 LRU 那样显式地“移动”} else {// key 不存在,需要插入新 key// 检查容量是否已满if (this.cap <= keyToVal.size()) {// 容量已满,需要淘汰一个 keyremoveMinFreqKey();}// 插入新的 key 和 valuekeyToVal.put(key, value);// 新 key 的初始频次为 1keyToFreq.put(key, 1);// 将新 key 加入频次为 1 的集合中freqToKeys.putIfAbsent(1, new LinkedHashSet<>());freqToKeys.get(1).add(key);// 插入新 key 后,最小频次一定是 1this.minFreq = 1;}}/* 增加 key 对应的频次 */private void increaseFreq(int key) {int freq = keyToFreq.get(key); // 获取当前频次// 更新 key 的频次keyToFreq.put(key, freq + 1);// 从旧频次的 key 集合中移除 keyLinkedHashSet<Integer> oldFreqKeys = freqToKeys.get(freq);oldFreqKeys.remove(key);// 将 key 加入新频次的 key 集合中freqToKeys.putIfAbsent(freq + 1, new LinkedHashSet<>());freqToKeys.get(freq + 1).add(key);// 检查旧频次的 key 集合是否为空if (oldFreqKeys.isEmpty()) {// 如果为空,则从 freqToKeys 中移除该频次条目freqToKeys.remove(freq);// 如果移除的这个频次恰好是 minFreq,则需要更新 minFreqif (freq == this.minFreq) {// 新的 minFreq 变成了 freq + 1this.minFreq++;}}}/* 淘汰一个最小频次且最旧的 key */private void removeMinFreqKey() {// 获取最小频次对应的 key 集合 (按插入顺序)LinkedHashSet<Integer> keyList = freqToKeys.get(this.minFreq);// 第一个元素就是最旧的 keyint deletedKey = keyList.iterator().next();// 从 key 集合中移除keyList.remove(deletedKey);// 检查移除后集合是否为空if (keyList.isEmpty()) {// 如果为空,则从 freqToKeys 中移除该频次条目freqToKeys.remove(this.minFreq);// 注意:这里不需要更新 minFreq// 因为 removeMinFreqKey() 只在 put 新元素且容量满时调用// 而 put 新元素后 minFreq 会被强制设为 1,所以旧的 minFreq 是否有效已不重要}// 从 keyToVal 和 keyToFreq 中移除该 keykeyToVal.remove(deletedKey);keyToFreq.remove(deletedKey);}
}
关键点总结 (LFU):
-
get 操作:通过 keyToVal 获取值,然后调用 increaseFreq 更新频率相关信息。
-
put 操作:
- 若 Key 存在:更新 keyToVal 中的值,调用 increaseFreq。
- 若 Key 不存在:检查容量,若满则调用 removeMinFreqKey 淘汰;然后,在 keyToVal, keyToFreq (设为1), freqToKeys (添加到freq=1的集合) 中添加新 Key,并将 minFreq 更新为 1。
-
increaseFreq 核心逻辑:更新 keyToFreq,从旧频次的 LinkedHashSet 中移除 Key,添加到新频次的 LinkedHashSet (如果需要则创建)。如果旧频次集合变空且它曾是 minFreq,则递增 minFreq。
-
removeMinFreqKey 核心逻辑:从 freqToKeys 中获取 minFreq 对应的 LinkedHashSet,移除其第一个元素(最旧的),并同步更新所有相关的 Map。如果集合变空,则移除该频次条目。
三、LRU vs LFU
- LRU: 关注最近访问时间,实现相对简单(LinkedHashMap 或 HashMap+DLL)。适合访问模式有较强时间局部性的场景。
- LFU: 关注访问频率,并结合时间作为次要淘汰标准(频率相同时淘汰最旧的)。实现更复杂,需要维护频率信息和访问时序。适合需要保留高频访问数据,即使它不是最近访问的场景。
相关文章:
深入理解缓存淘汰策略:LRU 与 LFU 算法详解及 Java 实现
一、LRU (Least Recently Used - 最近最少使用) LRU 策略的核心思想是:当缓存空间不足时,优先淘汰最近最长时间未被访问的数据。它基于“时间局部性”原理,即最近被访问的数据,在未来被访问的概率也更高。 LeetCode 146. LRU 缓…...
小智项目架构分析
小智代码架构 .github 这就是github项目上拉下来的一些信息 没什么好看的,这跟项目代码无关 .build 编译时生成的文件,没什么可看的,与项目代码无关 .main 主要的代码都在这里面了 .managed_components 这里是小智用到的一些第三方移植…...
基于 SSE 和分块传输的 Uniapp 微信小程序 实现 流式传输 对话
最近的项目是做微信小程序的一个对话框,接入DeepSeek,实现实时对话一个功能。 主要用到的技术点为: 1. Server-Sent Events (SSE) 技术: 在请求头中设置了 ‘X-DashScope-SSE’: ‘enable’,启用了SSE协议 服务器以事…...
[OS] POSIX C库介绍
POSIX C 库可以理解为 Unix/Linux系统的"标准化工具包",用一句话概括就是: 👉 它提供了一套跨Unix系统的统一编程接口,让开发者用同一份代码能在不同系统(如Linux、macOS)中运行。 核心组成&…...
<uniapp><插件><UTS>在uniapp中,创建自己的插件并发布到uni插件市场
前言 本专栏是基于uniapp实现手机端各种小功能的程序,并且基于各种通讯协议如http、websocekt等,实现手机端作为客户端(或者是手持机、PDA等),与服务端进行数据通讯的实例开发。 发文平台 CSDN 环境配置 系统&…...
深度学习前沿探秘:Transformer 模型与多领域应用
技术点目录 注意力(Attention)机制详解自然语言处理(NLP)领域的Transformer模型详解计算视觉(CV)领域的Transformer模型详解时间序列建模与预测的大语言模型目标检测算法详解目标检测的大语言模型语义分割的…...
介绍下Nginx的作用与请求转发机制
引言 最近笔者在业务中遇到了Nginx轮训策略使用不当导致后端服务的压力增加,从而导致容器CPU资源不足,响应超时的问题; 但由于对Nginx的了解仅限与作为反向代理使用,所以借用GPT工具整理了Nginx的作用以及请求转发机制ÿ…...
Sql刷题日志(day6)
一、笔试 1、insert ignore:在插入数据时忽略主键冲突或其他唯一性约束冲突。 如果插入的记录会导致主键冲突(如 actor_id 已存在),该语句不会报错,而是直接忽略插入操作 语法: INSERT IGNORE INTO tab…...
Ajax 提交表单与文件上传
目录 一、Ajax 提交表单1.1 基本原理1.2 HTML 表单示例1.3 JavaScript 示例(使用 fetch API)二、Ajax 文件上传2.1 基本原理2.2 HTML 文件上传表单示例2.3 JavaScript 示例(使用 fetch API)三、后端处理示例(以 Node.js + Express 为例)3.1 安装依赖3.2 创建服务器文件四…...
【零基础入门】ASP.NET Core快速搭建第一个Web应用
一、为什么选择ASP.NET Core? 跨平台支持:可在Windows/macOS/Linux系统运行 高性能:比传统ASP.NET框架快10倍以上 开源生态:活跃的开发者社区和丰富的NuGet包 云原生支持:完美适配Docker和Kubernetes部署 二、开发…...
盒子模型
1.1看透网页布局的本质 1.2盒子模型的组成部分 css盒子模型本质是一个盒子,封装周围的html元素,它包括边框 外边距 内边距和实际内容。 padding:盒子与内容间的距离margin:盒子与盒子间的距离 1.3border边框 1.border-width 边…...
厚铜PCB如何兼顾质量与成本?供应商设计规范执行的黄金平衡点
厚铜电路板供应商需要遵循一系列设计规范,以确保所提供的电路板符合行业标准和客户要求。以下是一些需要遵循的设计规范: 1. 电路板尺寸和形状:厚铜电路板供应商需要按照客户提供的规格和要求来设计电路板的尺寸和形状。一般来说,…...
Kafka 配置参数性能调优建议
文章目录 1、生产者调优batch.size(重要)linger.mscompression.typeacks(重要)buffer.memorymax.in.flight.requests.per.connection(重要)message.max.bytes(重要) 2、消费者调优fe…...
Java读Excel:解析阿里云easyExcel导入文件的行号
文章目录 引言I 解析阿里云easyExcel导入文件的行号声明解析对象的基类判断Excel解析对象类型是否包含继承某个类 isAssignableFromJava 转换list类型并设置下标到元素对象属性II 封装excel 文件读取excel 文件读取用法文件导入上下文III 参数校验工具类校验参数是否合法 (jaka…...
Vuex持续保存数据 页面刷新不丢失 vuex-persistedstate
vuex可以进行全局的状态管理,但刷新后刷新后数据会消失,这是我们不愿意看到的。怎么解决呢,我们可以结合本地存储做到数据状态持久化,但是太麻烦每次都要操作,强烈建议使用插件利用vuex-persistedstate插件. 安装 npm …...
.NET8配置组件
一、组件的概念 含义:用于从配置文件中读取配置的组件,叫做配置组件。简单来说, 就是从xml、json、yaml、txt等文件中读取配置的组件。主要采用微软提供的 Microsoft.Extensions.Configuration 二、组件的使用 1、json配置读取 (1)、在Dunk.Common.Project.Configuratio…...
加密算法:ed25519和RSA
ed25519 和 RSA 是两种不同的非对称加密算法,常用于 SSH 密钥认证。以下是它们的对比和选择建议: 1. 算法对比 特性ed25519RSA (4096-bit)安全性更高(基于椭圆曲线密码学 ECC)高(依赖大数分解难度)密钥长度固定 256 位(公钥/私钥更短)通常 2048/4096 位(公钥较大)性能…...
递归、搜索和回溯算法《递归》
在之前的优选算法当中我们已经学习了一些基本的算法,那么接下来我们就要来学习算法当中的一大重要章节——递归、搜索和回溯算法,其实也就是大家常常听到的dfs、bfs;其实本质就是递归,在学习搜索、回溯等算法的过程当中我们会先来…...
构建“云中”高并发:12306技术改造的系统性启示
作为曾参与12306余票查询系统高并发升级的技术从业者,笔者注意到公众对于12306底层技术常存在认知盲区。为破解这一迷思,特此分享十年前的架构解密文献(该技术之前名叫 gemfire 现已晋升为Apache顶级项目Geode,代码库详见…...
升级xcode15 报错Error (Xcode): Cycle inside Runner
升级xcode15后报错 Could not build the precompiled application for the device. Error (Xcode): Cycle inside Runner; building could produce unreliable results. This usually can be resolved by moving the shell script phase Thin Binary so that it runs before th…...
gradle-tasks.register(‘classesJar‘, Jar)解析
在使用gradle作为构建工具的android或者java web项目中,我们经常能遇到以下格式 tasks.register(classesJar, Jar) {from "$buildDir/intermediates/javac/release/classes" // 假设使用 release 构建变体 }artifact sourcesJar使用伪代码解释 class Cu…...
深度对比:Objective-C与Swift的RunTime机制与底层原理
1. RunTime简介 RunTime(运行时)是指程序在运行过程中动态管理类型、对象、方法等的机制。Objective-C 和 Swift 都拥有自己的运行时系统,但设计理念和实现方式有很大不同。理解 RunTime 的底层原理,是掌握 iOS 高级开发的关键。…...
升级Xcode16,flutter项目报错
升级xcode16后发现原来的项目运行不了了,flutter的版本是3.3.1 保错:[ 304 ms] Could not build the precompiled application for the device. [ 16 ms] Error (Xcode): linker command failed with exit code 1 (use -v to see invocation) 1、找到本地…...
MCU内存映射技术详解
MCU内存映射技术详解 1. 引言 内存映射是微控制器(MCU)系统设计中的核心概念,它决定了MCU如何访问和管理内存资源。通过内存映射,处理器可以将物理设备的地址空间映射到自己的逻辑地址空间中,实现对各种硬件资源的统一访问。本文将深入探讨…...
Mac搭建Flutter IOS环境详细指南
目录 1. 准备工作 2. 下载Flutter SDK: 2.1 配置环境 2.2 解决环境报错 zsh:command not found:flutter 2.3、再使用source命令重新加载一下:【source ~/.zshrc】,下次再编辑这个文件就可以直接执行:【open ~/.zshrc】 2.4、执行【flut…...
计算机基础—(九道题)
1. 流程控制题 编写一个程序,输入一个整数,判断它是否是素数(质数)。 如果是素数,输出Yes,否则输出No。 #include <stdio.h> int main() /* 1. 流程控制题编写一个程序,输入一个整数&…...
蓝桥杯2025年第十六届省赛真题-可分解的正整数
其实只有1不符合要求,因为-1010,作为对称结构,任何数都可以改成加法,比如4-3-2-101234,但因为最小连续的数为3,1恰好在里面,所以1不行。 #include<bits/stdc.h> using namespace std; #define int l…...
Linux虚拟机无法重启网络
这是为什么啊?试了很多种方法都还是失败。 这是本机vmware8的网络配置 这是linux虚拟机的nat配置 这是虚拟机里静态配置的网络 有没有可以答疑解惑一下的?...
8.Android(通过Manifest配置文件传递数据(meta-data))
配置文件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"><applicationandroid:allowBackup"tr…...
17:00开始面试,17:08就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到4月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…...
Docker 常用命令(涵盖多个方面)
Docker 命令完整列表(表格形式) 类别 命令 描述 示例 Docker 服务管理 sudo systemctl start docker 启动 Docker 守护进程 sudo systemctl start docker sudo systemctl stop docker 停止 Docker 守护进程,需先停止所有容…...
前缀树(Trie)(字典树)
做leetcode的时候看到前缀树,听都没听过,后来才知道前缀树就是字典树。之前学过,在OJ项目中用字典树来实现黑白名单限制。浅浅复习一下吧 用字典树来实现黑白名单限制 实现步骤 (1)定义黑名单 import java.util.Arra…...
word插入APA格式的参考文献
word插入APA格式的参考文献并实现交叉引用 1. 直接手写并采用超链接 2. 使用zotero插入参考文献后采用超链接(前提下载zotero和对应的插件) 1. 直接手写 APA格式生成 1. 在需要插入参考文献的地方手写格式,如下。 2. 生成书签 名字随便填的,&#x…...
n8n部署docker本地化备份和数据持久化和迁移问题
问题总结: 在一开始的操作中,你遇到的主要问题是 Docker 容器内的文件权限导致了文件无法正确写入和修改,尤其是在复制本地备份文件到容器内时。具体问题表现为: 复制文件后,容器内文件权限错误:你使用 do…...
绘制板块层级图
目录 【实验目的】 【实验原理】 【实验环境】 【实验步骤】 【实验总结】 【实验目的】 掌握数据文件读取掌握数据处理的方法实现板块层级图的绘制 【实验原理】 板块层级图(treemap)是一种基于面积的可视化方式,通过每一个板块&…...
国标云台控制状态
1.基本概念 国标联网系统的信息传输、交换、控制方面的都是通过SIP服务器负责通讯得,SIP负责信令流逐级转发。其中最重要的一部分就是和摄像机进行信令交互。 像安全注册、实时视音频点播、历史视音频的回放等应用的会话控制采用IETFRFC3261规定的Register、Invite等…...
PostgreSQL与MySQL哪个适合做时空数据分析?
PostgreSQL与MySQL的定位与区别 定位差异:功能导向与性能优先 PostgreSQL和MySQL作为两大主流开源数据库,其核心设计理念和适用场景存在显著差异。PostgreSQL定位为 对象-关系型数据库(ORDBMS) ,强调功能完备性与标准…...
uniapp利用生命周期函数实现后台常驻示例
在 Uniapp 中,利用生命周期函数实现“后台常驻”主要是通过监听应用的前后台状态变化( onHide 和 onShow ),并结合 定时器、后台任务或状态保持逻辑 来实现。但需注意: 纯前端 JS 代码无法突破系统对后台应用的限制&am…...
JAVA设计模式——(八)单例模式
JAVA设计模式——(八)单例模式 介绍理解实现饿汉式懒汉式 应用 介绍 确保一个类只存在一个实例。 理解 就是一个实例,new出来的一个,很简单。不过单例模式分为了懒汉式和饿汉式,其中也有线程安全的实现方式和线程不…...
【亚马逊云】AWS Wavelength 从理论讲解到实验演练
一、什么是 AWS Wavelength? Wavelength——一种新型的 AWS 基础设施,旨在运行需要低延迟或边缘弹性的工作负载。 AWS Wavelength 将按需计算和存储服务引入通信服务提供商网络,使客户能够构建和部署满足其数据驻留、低延迟和弹性要求的应用…...
Uniapp:vite.config.js全局配置
目录 一、基本概述二、配置自动引入插件一、基本概述 vite.config.js 是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被自动加载,一般用于配置 vite 的编译选项 二、配置自动引入插件 在项目命令行终端中执行如下代码 npm install unplugin-auto-import…...
Springboot整合阿里云腾讯云发送短信验证码 可随时切换短信运营商
本文描述了在springboot项目中整合实现对接阿里云 和 腾讯云的短信验证码发送,可通过更改配置文件达到切换短信发送运营商(申请签名、短信模版这些本文不在叙述)。 首先看下大体结构: 一、需要导入的jar <dependency><groupId>com.…...
git 查看用户信息
在 Git 中查看用户信息是一项常见的任务,可以帮助你确认当前仓库的配置或全局的 Git 配置是否正确设置。你可以通过多种方式来查看这些信息。 查看全局用户信息 全局用户信息是应用于所有 Git 仓库的默认设置。要查看全局用户信息,可以使用以下命令&am…...
JAVA基础:Collections 工具类实战指南-从排序到线程安全
在 Java 开发中,集合类几乎贯穿每一个项目,而Collections工具类提供了一系列强大的方法,用于操作和增强集合的功能。无论是排序、查找还是线程安全的封装,Collections工具类都是提升代码效率和质量的重要工具。 一、Collections …...
【计算机视觉】TorchVision 深度解析:从核心功能到实战应用 ——PyTorch 官方计算机视觉库的全面指南
TorchVision 深度解析:从核心功能到实战应用 ——PyTorch 官方计算机视觉库的全面指南 1. TorchVision 项目概览核心模块 2. 实战案例:10 大应用场景详解案例 1:使用预训练 ResNet 进行图像分类代码实现常见问题相关论文 案例 2:加…...
case和字符串操作
使用if选择结构 if [];then elif [];then #注意这个地方,java是else if else ; fi 使用for循环结构 使用for循环,语法结构如下所示: for 变量名 in 值1 值2 值3 #值的数量决定循环任务的次数 do命令序列 done#循环输出1到10 for i in {1..10} #注…...
Golang|外观模式和具体逻辑
最终返回的是Document的切片,然后取得Bytes自己再去做反序列化拿到文档的各种详细信息。 外观模式是一种结构型设计模式,它的目的是为复杂的子系统提供一个统一的高层接口,让外部调用者(客户端)可以更简单地使用子系统…...
关于kafka
1.为什么需要消息队列 举个经典的例子。 你是一个网购达人,经常在网上购物。快递小哥到了你的小区后,立刻给你打电话说:“你的快递到了,请马上来取。” 但你是一个合格的牛马,在上班,不方便取快递&#…...
OpenCV 图形API(67)图像与通道拼接函数-----水平拼接(横向连接)两个输入矩阵(GMat 类型)函数concatHor()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 该函数用于水平拼接两个 GMat 矩阵,要求输入矩阵的行数必须一致: GMat A { 1, 4,2, 5,3, 6 }; GMat B { 7, 10,8, 11,9, 12 }; GM…...
夜莺 v8.0.0-beta.10 部署
夜莺 v8.0.0-beta.10 部署 1. mariadb-server2. Redis安装3. 下载 n9e-v8.0.0-beta.10-linux-amd64.tar.gz设置 root 用户密码配置文件 配置mariadb的登录密码导入数据库表结构配置为 systemd 启动服务重新加载 systemd配置日志 访问夜莺VictoriaMetrics 时序数据库安装接入数据…...