单例模式与消费者生产者模型,以及线程池的基本认识与模拟实现
前言
今天我们就来讲讲什么是单例模式与线程池的相关知识,这两个内容也是我们多线程中比较重要的内容。其次单例模式也是我们常见设计模式。
单例模式
那么什么是单例模式呢?上面说到的设计模式又是什么?
其实单例模式就是设计模式的一种。我们在学习过程中会不断编程,设计合理的代码结构和逻辑。后来就有许多种比较常用的结构,这时就有一些大佬总结这些常用的代码结构,逻辑,并给这些结构命名成不同的模式,而这些模式就是我们所说的单例模式。那么接下来我们就来学习一下,其中之一的单例模式。
单例模式就是在某个类程序中保证某个实类对象在程序中只有一个实例,而且他的实例是不能new出来的,你只能通过其提供的getInstance方法来获取他的实例化对象。单例模式也分为两个经典的代码编写方式。“懒汉模式”和“饿汉模式”。
饿汉模式
class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
如上代码:我们在要实现单例模式的类中,直接创建一个本类的成员变量,然后就是最牛的“点睛之笔”了。
我们直接将构造方法私有化,那么这时其它类就无法通过构造方法new出这个类的实例化对象了。
什么是饿汉模式呢?这里重点注意“饿”这个字,因为“饿”所以非常急,在类中直接将成员变量在定义时就直接实例化。
懒汉模式
class Singleton {private static volatile Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
我们可以很清楚的看到,懒汉模式相较于饿汉模式代码多了些,因为懒汉模式在多线程下需要加锁,如果不加锁可能有多个线程同时调用getInstance()方法就有可能创建出多个实例,这就不符合单例模式的设定了。而且还加上了volatile 保证了内存的可见性也是防止线程安全的发生。
如何理解两层 if判断 ?
最里层的 if ,判断该类是否被实例化,如果没有实例化即 ==null 我们就new一个对象并返回,如果已经实例化过就直接返回。
最外层的 if 我们知道加锁和开锁也是一个开销比较高的事情,我们就要经尽量减少加锁开锁的次数,当我们的实例已经创建了,我们在就可以直接返回了,但是如果不加这一层 if,程序就会加锁判断部分,这就导致无用开销,所以我们就可以再加一层判断。这一层就是为了防止无用的加锁。
阻塞队列
什么是阻塞队列呢?
正如字面他是一个可以阻塞的队列,他跟普通队列一样有着FIFO(“先进先出”)出的性质。但是他会在两种情况下发生阻塞。
- 当队列满时,如果还有元素要入队列那么就会发生阻塞。
- 当队列为空时,如果有出队列的请求那么也会发生阻塞。
阻塞队列的一个经典应用场景就是“生产者消费者模型”,这也是一个非常典型的开发模型。
生产者消费者模型
生产者消费者模型就是运用一个容器来解决生产者和消费者的强耦合的问题。
生产者和消费者之间不直接通讯,通过阻塞队列来进行通讯,所以生产者生产完数据后不在需要等待消费者处理,而是直接将数据丢给阻塞队列,消费者也不找生产者要数据,而是直接从阻塞队列中取数据。这样就成功的对生产者和消费者进行解耦。
除了解耦,阻塞队列还起到了缓冲区的作用,阻塞队列就平衡了生产者和消费者的处理能力,起到了消峰填谷。比如在某些购物日,或秒杀抢购的情况下,如果没有阻塞队列,突然暴增的请求,如果让服务器直接去处理,我们的服务器有可能会处理不过来,而导致奔溃,但是如果有了阻塞队列我们就可以把请求放进阻塞队列中,再由消费者线程慢慢处理订单。
Java标准库中的阻塞队列
在Java标准库中我们有阻塞队列 BlockingQueue(这是一个接口),其中他的实现类是LinkedBlockingQueue
其中这个队列中我们有put()方法表示入队列,还有take()出队列,者两个方法是具有阻塞功能的.
当然这个队列也有offer,poll,peek,等方法,但这都是不具有阻塞功能的。
下面我们通过编写一段代码,象形的展示了阻塞队列的阻塞功能,非常直观。
我们先是创建第一个消费者线程,让其不断的从阻塞队列中去数据,但刚开始阻塞队列中没有数据,所以他就会进行阻塞,所以我们创建了第二个线程(生产者线程)我们每隔一段时间生成一个数据,并放进队列中,这时生产者线程就可会马上将队列里的数据给取出来了。
import java.util.Random;
import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;public class Main {public static void main(String[] args) throws InterruptedException {BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>();Thread customer = new Thread(() -> {while (true) {try {int value = blockingQueue.take();System.out.println("消费元素: " + value);} catch (InterruptedException e) {e.printStackTrace();}}}, "消费者");customer.start();Thread producer = new Thread(() -> {Random random = new Random();while (true) {try {int num = random.nextInt(1000);System.out.println("⽣产元素: " + num);blockingQueue.put(num);Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}, "⽣产者");producer.start();customer.join();producer.join();}
}
阻塞队列的模拟实现
这里主要通过wait()进行阻塞,当我们发现队列满时,或空时,我们的put方法和take()方法就要进行阻塞,也就是调用wait()方法以及我们的synchronize,但是需要注意的是我们这里的判断尽量还是用while循环来进行判断,因为在我们notifyAll 的时候, 该线程从 wait 中被唤醒,但是紧接着并未抢占到锁. 当锁被抢占的时候, 可能⼜已经队列满了
- 假设队列初始是满的,生产者 P1 调用
wait()
并释放锁。 - 消费者 C1 抢到锁,消费一个数据,调用
notifyAll()
,唤醒 P1。 - 但此时可能有另一个生产者 P2 抢先抢到锁,并插入数据,导致队列又满了。
- 如果 P1 用
if
,它会直接执行items[tail] = value
(因为之前检查size == items.length
是true
,但被唤醒后未重新检查),导致队列溢出。 - 用
while
会重新检查条件,发现队列还是满的,继续wait()
。
如下代码:我们通过synchroniz关键字和wait()方法,完成了阻塞队列。
class BlockingQueue1{private int[] items = new int[1000];private volatile int size = 0;private volatile int head = 0;private volatile int tail = 0;public void put(int value) throws InterruptedException {synchronized (this) {// 此处最好使⽤ while.// 否则 notifyAll 的时候, 该线程从 wait 中被唤醒,// 但是紧接着并未抢占到锁. 当锁被抢占的时候, 可能⼜已经队列满了// 就只能继续等待while (size == items.length) {wait();}items[tail] = value;tail = (tail + 1) % items.length;size++;notifyAll();}}public int take() throws InterruptedException {int ret = 0;synchronized (this) {while (size == 0) {wait();}ret = items[head];head = (head + 1) % items.length;size--;notifyAll();}return ret;}public synchronized int size() {return size;}// 测试代码public static void main(String[] args) throws InterruptedException {BlockingQueue1 blockingQueue = new BlockingQueue1();Thread customer = new Thread(() -> {while (true) {try {int value = blockingQueue.take();System.out.println(value);} catch (InterruptedException e) {e.printStackTrace();}}}, "消费者");customer.start();Thread producer = new Thread(() -> {Random random = new Random();while (true) {try {blockingQueue.put(random.nextInt(10000));} catch (InterruptedException e) {e.printStackTrace();}}}, "⽣产者");producer.start();customer.join();producer.join();}
}
定时器
定时器是什么呢?就是一个可以根据时间定时执行任务的容器吧
定时器的主要构成:
- 一个带优先级的队列( (不要使⽤ PriorityBlockingQueue, 容易死锁 )
- 其中队列中的每一个元素是一个Task
- Task中存在一个带有时间属性,其中队首元素是即将执行的元素。
- 还有存在一个工作线程worker不断扫描队首元素,,检查时间是否以及到了,是否开始执行
定时器的模拟实现:
首先我们先对MyTask重写我们的compareTo方法,如果不在这里重写,就要在创建队列的时候对其构造方法传入一个比较器的参数即(Comparable<MyTask>)。
且MyTask中是定义一个long类型的属性time,我们就可以利用时间戳来表示他要在何时执行任务。
然后定义构造方法,其中包含两个参数,第一个就是当前的时间戳,第二个是多少毫秒后执行当前任务。
然后我们在提交任务去定时器时,只需要传入这两个参数给schedule即可。在方法内部我们会先根据这两个参数
构造出一个Mytask,然后放进优先级队列中。
class MyTask implements Comparable<MyTask> {public Runnable runnable;// 为了⽅便后续判定, 使⽤绝对的时间戳.public long time;public MyTask(Runnable runnable, long delay) {this.runnable = runnable;// 取当前时刻的时间戳 + delay, 作为该任务实际执⾏的时间戳this.time = System.currentTimeMillis() + delay;}@Overridepublic int compareTo(MyTask o) {// 这样的写法意味着每次取出的是时间最⼩的元素.// 到底是谁减谁?? 俺也记不住!!! 随便写⼀个, 执⾏下, 看看效果~~return (int)(this.time - o.time);}
}class MyTimer {// 核⼼结构private PriorityQueue<MyTask> queue = new PriorityQueue<>();// 创建⼀个锁对象private Object locker = new Object();public void schedule(Runnable command, long after) {// 根据参数, 构造 MyTask, 插⼊队列即可.synchronized (locker) {MyTask myTask = new MyTask(command, after);queue.offer(myTask);locker.notify();}}// 在这⾥构造线程, 负责执⾏具体任务了.public MyTimer() {Thread t = new Thread(() -> {while (true) {try {synchronized (locker) {// 阻塞队列, 只有阻塞的⼊队列和阻塞的出队列, 没有阻塞的查看队⾸元素.while (queue.isEmpty()) {locker.wait();}MyTask myTask = queue.peek();long curTime = System.currentTimeMillis();if (curTime >= myTask.time) {// 时间到了, 可以执⾏任务了queue.poll();myTask.runnable.run();} else {// 时间还没到locker.wait(myTask.time - curTime);}}} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}
线程池
线程池是什么?通俗来讲就是先创建好一些线程,当我们需要创建线程时,直接从线程池里取即可,不需要在创建,而且用完后直接将线程返回给线程池,这样就减少了我们创建和销毁线程的开销。
Java标准库中的线程池
Executors
是一个工厂类,提供了创建各种类型线程池的静态方法
固定大小线程池
- ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads);
- 固定数量的线程
- 无界任务队列(LinkedBlockingQueue)
- 适用于负载较重的服务器
单线程线程池
- ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
- 只有一个工作线程
- 保证任务顺序执行
- 无界任务队列
可缓存线程池
- ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
- 线程数量根据需要自动调整
- 空闲线程60秒后回收
- 适用于执行大量短期异步任务
定时任务线程池
- ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);
- 核心线程数固定,非核心线程数无限制
- 支持定时及周期性任务执行
如下代码就可以创建一个含有10个线程的线程池,其中
ExecutorService executorService = Executors.newFixedThreadPool(10);
从上上面代码可以很容易看出Executors.newFixedThreadPool(10)的返回值时一个ExecutorService,然后我们可以往线程池里提交任务执行了。
如下截图:我们调用submit方法时,只需要传入一个Runable的对象即可,跟创建线程的方法相似。
mport java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Main {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(10);executorService.submit(()->System.out.println("一个人任务"));}
}
相关文章:
单例模式与消费者生产者模型,以及线程池的基本认识与模拟实现
前言 今天我们就来讲讲什么是单例模式与线程池的相关知识,这两个内容也是我们多线程中比较重要的内容。其次单例模式也是我们常见设计模式。 单例模式 那么什么是单例模式呢?上面说到的设计模式又是什么? 其实单例模式就是设计模式的一种。…...
微信小程序通过mqtt控制esp32
目录 1.注册巴法云 2.设备连接mqtt 3.微信小程序 备注 本文esp32用的是MicroPython固件,MQTT服务用的是巴法云。 本文参考巴法云官方教程:https://bemfa.blog.csdn.net/article/details/115282152 1.注册巴法云 注册登陆并新建一个topicÿ…...
QML、Qt Quick 、Qt Quick Controls 2
一、概念 基本关系 QML 是声明式语言,用于描述用户界面。声明式语法(类似JSON+JavaScript),定义UI结构和行为。 Qt Quick 是 QML 的标准库,提供基本类型和功能。提供QML语言运行时的基础能力,相当于QML的"标准模板库(STL)"。 Quick Controls 2 是基于 Qt Quic…...
基于maven-jar-plugin打造一款自动识别主类的maven打包插件
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
利用 HEMT 和 PHEMT 改善无线通信电路中的增益、速度和噪声
本文要点 高电子迁移率晶体管 (High electron mobility transistors ,HEMTs) 和应变式异质接面高迁移率晶体管(pseudomorphic high electron mobility transistors ,PHEMTs) 因其独特的、可提高性能的特点而…...
探秘C#用户定义类型:突破预定义的边界
在C#的编程世界里,除了系统提供的16种预定义类型,开发者还拥有强大的自主能力——创建自己的用户定义类型。这大大拓展了编程的灵活性和可扩展性,让开发者能根据具体需求定制数据结构和功能。 六种用户定义类型 类类型(class&am…...
idea中导入从GitHub上克隆下来的springboot项目解决找不到主类的问题
第一步:删除目录下的.idea和target,然后用idea打开 第二步:如果有需要,idea更换jdk版本 原文链接:https://blog.csdn.net/m0_74036731/article/details/146779040 解决方法(idea中解决)&#…...
北理工宫某的瓜ppt下载地址
关于“北理工宫某瓜”PPT下载地址相关技术探讨 摘要:本文围绕“北理工宫某瓜”事件中PPT下载地址相关情况展开分析,探讨了网络资源传播的技术机制、涉及的网络安全问题以及围绕此类资源分享应遵循的规范和注意事项,旨在从技术角度对这类网络…...
[论文阅读]Making Retrieval-Augmented Language Models Robust to Irrelevant Context
Making Retrieval-Augmented Language Models Robust to Irrelevant Context [2310.01558v2] Making Retrieval-Augmented Language Models Robust to Irrelevant Context 检索增强语言模型(RALMs),它包含一个检索机制,以减少将…...
论文阅读:2023 arxiv A Survey of Reinforcement Learning from Human Feedback
A Survey of Reinforcement Learning from Human Feedback https://arxiv.org/pdf/2312.14925 https://www.doubao.com/chat/3506943124865538 速览 这篇论文是关于“从人类反馈中进行强化学习(RLHF)”的综述,核心是讲如何让AI通过人类反…...
【图像处理基石】什么是去马赛克算法?
RAW数据的Demosaic算法(去马赛克算法)是图像处理中的关键技术,主要用于将图像传感器(如数码相机、手机摄像头)采集的原始马赛克数据恢复为完整的RGB三通道图像。 1. RAW数据的特性 马赛克结构:图像传感器…...
transformer注意力机制
单头注意力机制 import torch import torch.nn.functional as Fdef scaled_dot_product_attention(Q, K, V):# Q: (batch_size, seq_len, d_k)# K: (batch_size, seq_len, d_k)# V: (batch_size, seq_len, d_v)batch_size: 一次输入的句子数。 seq_len: 每个句子的词数。 d_mo…...
Ubuntu 22.04 更换 Nvidia 显卡后启动无法进入桌面问题的解决
原显卡为 R7 240, 更换为 3060Ti 后, 开机进桌面时卡在了黑屏界面, 键盘有反应, 但是无法进入 shell. 解决方案为 https://askubuntu.com/questions/1538108/cant-install-rtx-4060-ti-on-ubuntu-22-04-lts 启动后在开机菜单中(如果没有开机菜单, 需要按shift键), 进入recove…...
ROS机器人开发实践->机器人建模与仿真
前言: 这篇博客知识一个整体性的了解对于机器人建模和仿真,更多详细的细节,见 6.4.2 Xacro_语法详解 Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 一、整体框架 机器人模型分为两个部分具体的形状和插件。有了这个具体的形状…...
中国占全球工业机器人装机量的52%,国产机器人崛起加速洗牌,拆分机器人业务独立上市,软硬件协同增强,AI工业机械臂催生业务再增长
一、内部战略优化:聚焦核心业务与释放增长潜力 业务协同效应有限 ABB的机器人业务(全球市场份额第二)与集团其他业务(如电气化、过程自动化)的协同性较低。机器人业务专注于柔性制造和智能自动化,而其他业务更偏向能源效率和大型工业系统。分拆后,ABB集团可更聚焦于电气…...
C#森林中的兔子(力扣题目)
C#森林中的兔子(力扣题目) 题目介绍 森林中有未知数量的兔子。提问其中若干只兔子 “还有多少只兔子与你(指被提问的兔子)颜色相同?” ,将答案收集到一个整数数组 answers 中,其中 answers[i] 是第 i 只兔子的回答。 给你数组…...
OSPF特殊区域
四种特殊区域 1、stub 2、完全stub 3、nssa 4、完全nssa 作用:用于优化OSPF的LSDB空间 stub: [R2-ospf-1-area-0.0.0.1]stub //配置一个区域为stub区域 只在ABR上配置的话会导致OSPF邻居关系断开,因为此时Option选项中Nbit和Ebit置位不一致所…...
深入理解 CICD 与 Jenkins 流水线:从原理到实践
前言:在当今数字化飞速发展的时代,软件开发行业的竞争日益激烈。为了能够快速响应市场需求,及时交付高质量的软件产品,开发团队们不断探索和采用新的开发模式与工具。CICD(持续集成、持续交付 / 部署)作为一…...
1.Vue自动化工具安装(Vue-cli)
目录 1.node.js 安装: 2 npm 安装 3 安装Vue-cli 4总结: 一般情况下,单文件组件,我们运行在 自动化工具vue-CLI中,可以帮我们编译单文件组件。所以我们在学习时一般需要在系统中先搭建vue-CLI工具 下面就是一些我…...
前端亮点:大文件上传技术详解及问题解析
大片文件上传 文件上传 大片文件上传需考虑问题 一、核心实现步骤 分片唯一标识计算 (优化比较时间) • Hash生成:使用SparkMD5或crypto.subtle.digest计算文件整体Hash(秒传依据)及分片Hash(断点续传依据)。 • 优化:通过Web Worker多线程计算,避免主线程阻塞(如…...
每日一题——最小测试用例集覆盖问题
最小测试用例集覆盖问题(C语言实现) 问题描述 假设我们有一系列测试用例,每个测试用例会覆盖若干个代码模块。 我们使用一个二维数组来表示这些测试用例的覆盖情况: 如果某个测试用例 i 能覆盖代码模块 j,则数组中…...
React 文章 分页
删除功能 携带路由参数跳转到新的路由项 const navigate useNavigate() 根据文章ID条件渲染...
【技术派后端篇】Redis实现统计计数
在互联网项目中,计数器有着广泛的应用场景。以技术派项目为例,诸如文章点赞数、收藏数、评论数以及用户粉丝数等都离不开计数器的支持。在技术派源码中,提供了基于数据库操作记录实时更新和基于 Redis 的 incr 特性实现计数器这两种方案&…...
NHANES指标推荐:RFM
文章题目:Higher relative fat mass was associated with a higher prevalence of gallstones in US adults DOI:10.1186/s12876-025-03715-3 中文标题:在美国成年人中,相对脂肪质量越高,胆结石患病率就越高 发表杂志&…...
嵌入式人工智能应用-第三章 opencv操作 4 灰度处理
嵌入式人工智能应用 嵌入式人工智能应用-第三章 opencv操作 4 灰度处理 嵌入式人工智能应用1 灰度处理2 算法2.1 均值方法2.2 最大值法2.3 分量法2.4 加权平均法(Weighted Average Method)2.5 系统自带方法 3 总结 1 灰度处理 图像灰处理即是将一幅彩色…...
AI Agent破局:智能化与生态系统标准化的颠覆性融合!
Hi!好久不见 云边有个稻草人-个人主页 热门文章_云边有个稻草人的博客-本篇文章所属专栏~ 目录 一、引言 二、AI Agent的基本概念 2.1 定义与分类 2.2 AI Agent的工作原理 2.3 示例代码:AI Agent的基本实现 三、AI Agent在企业数字化转型中的应用 …...
UniFlash以串口方式烧录MSPM0G3507(无需仿真器)
材料:MSPM0G3507黑钢版,只要有UART的其他版本亦可(PA14需接LED) 下载软件:UniFlash 9.1.0.5175,网址:UNIFLASH 软件编程工具 | 德州仪器 TI.com.cn 测试文件:MSPM0G30…...
坐标轴刻度QCPAxisTicker
一、QCPAxisTicker 概述 QCPAxisTicker 是 QCustomPlot 中控制坐标轴刻度生成和显示的基类,负责计算刻度位置和生成刻度标签。 二、主要派生类 类名描述QCPAxisTickerFixed固定步长的刻度生成器QCPAxisTickerLog对数坐标刻度生成器QCPAxisTickerPi专门显示π倍数…...
Spring Boot 版本与对应 JDK 版本兼容性
Spring Boot 版本与对应 JDK 版本兼容性 以下是 Spring Boot 主要版本与所需 JDK 版本的对应关系,以及长期支持(LTS)信息: 最新版本对应关系 (截至2024年) Spring Boot 版本发布日期支持的 JDK 版本备注3.2.x (最新)2023-11JDK 17-21推荐使用 JDK 173…...
【MySQL】MySQL的基础语法及其语句的介绍
1、基础语法 mysql -h【主机名】 -u【用户名】 -p //登录MySQL exit或quit; //退出MySQL show database; //查看MySQL下的所有数据库 use 【数据库名】; //进入数据库 show tables; //查看数据库下的所有表名 *MySQL的启动和关闭 &am…...
《汽车理论》第四章作业MATLAB部分
1.计算并绘制利用附着系数曲线和制动效率曲线 clc close all %空载(no load)-1 ;满载(full load)-2 m14080; m29290; hg10.845; hg21.170; L3.950; a12.100; a22.950; b1L-a1; b2L-a2; beta0.38; %利用附着系数与制动强度的关系曲线 z0:0.01:1; phi_f1L*beta.*z./(b1z*hg1);%前…...
SpringCloud实战
环境准备: 1. 一台虚拟机,部署好centos7操作系统、安装好docker 2. 使用docker安装mysql数据库且启动mysql容器 3. IDEA配置的JDK版本是11 4. 前端代码启动Nginx 一、单体架构和微服务的区别? 1. 单体架构 将业务的所有功能集中在一个项目中…...
Cribl 对Windows-xml log 进行 -Serialize-05
The Serialize Function Description The Serialize Function is designed to transform an events content into a predefined format. Steps - Adding a Serialize Function important Select the Add Function<...
鸿蒙ArkUI之布局实战,线性布局(Column,Row)、弹性布局(Flex)、层叠布局(Stack),详细用法
本文聚焦于ArkUI的布局实战,三种十分重要的布局,线性布局、弹性布局、层叠布局,在实际开发过程中这几种布局方法都十分常见,下面直接上手 线性布局 垂直布局(Column) 官方文档: Column-行列…...
缓存 --- 内存缓存 or 分布式缓存
缓存 --- 内存缓存 or 分布式缓存 内存缓存(In-Memory Cache)分布式缓存(Distributed Cache)内存缓存 vs 分布式缓存 内存缓存和分布式缓存是两种常见的缓存策略,它们在存储位置、访问速度和适用场景上有所不同。下面分…...
【Qt】QMainWindow类
🌈 个人主页:Zfox_ 🔥 系列专栏:Qt 目录 一:🔥 QMainWindow 概述 🦋 菜单栏🎀 具体使用🎀 综合案例 🦋 工具栏🦋 状态栏🦋 窗口布局&a…...
缓存 --- 缓存击穿, 缓存雪崩, 缓存穿透
缓存 --- 缓存击穿, 缓存雪崩, 缓存穿透 缓存击穿(Cache Breakdown)概念原理实际场景代码实现(互斥锁方案) 缓存雪崩(Cache Avalanche)概念原理实际场景代码实现(随机过期时间) 缓存…...
第五章 SQLite数据库:5、SQLite 进阶用法:ALTER 命令、TRUNCATE 操作、视图创建、事务控制和子查询的操作
1. SQLite ALTER 命令 SQLite 的 ALTER TABLE 命令允许在不完全重建表的情况下修改现有的表结构。通过 ALTER TABLE,您可以执行如重命名表名、添加新列等操作,但无法执行复杂的修改,如删除列或修改列的数据类型。 语法 重命名表 用于重命名…...
【2】Kubernetes 架构总览
Kubernetes 架构总览 主节点与工作节点 主节点 Kubernetes 的主节点(Master)是组成集群控制平面的关键部分,负责整个集群的调度、状态管理和决策。控制平面由多个核心组件构成,包括: kube-apiserver:集…...
【数据结构】红黑树
红黑树( R e d B l a c k T r e e Red\ Black\ Tree Red Black Tree)是一种自平衡二叉搜索树,也可以看作一种特化的 A V L AVL AVL 树(通过颜色规则来实现自平衡功能),都是在进行插入和删除操作时通过特定…...
ThreadLocal - 原理与应用场景详解
ThreadLocal 的基础概念 在 Java 的多线程世界里,线程之间的数据共享与隔离一直是一个关键话题。如果处理不当,很容易引发线程安全问题,比如数据混乱、脏读等。而 ThreadLocal 这个工具类,就像是为线程量身定制的 “私人储物柜”…...
VS Code 远程连接服务器:Anaconda 环境与 Python/Jupyter 运行全指南。研0大模型学习(第六、第七天)
VS Code 远程连接服务器:Anaconda 环境与 Python/Jupyter 运行全指南 在使用 VS Code 通过 SSH 远程连接到服务器进行开发时,尤其是在进行深度学习等需要特定环境的工作时,正确配置和使用 Anaconda 环境以及理解不同的代码运行方式非常关键。…...
chili3d调试6 添加左侧面板
注释前 一个一个注释看对应哪个窗口 无事发生 子方法不是显示的窗口 注释掉看看 没了 注释这个看看 零件页面没了 这个浏览器居然完全不用关的,刷新就重载了 注释看看 无工具栏版本 sidebar: 往框框里面加入 div({ className: style.input }, user_…...
Python变量全解析:从基础到高级的命名规则与数据类型指南
一、变量基础与内存机制 1.1 变量的三元构成 每个Python变量由三个核心要素构成: 标识(Identity):对象的内存地址,通过id(obj)获取(如id(name)输出0x5a1b2c3d)类型(Type&am…...
组装一台intel n95纯Linux Server服务器
前言 笔者自己的电脑是macmini m4,平时都是使用虚拟机来充当Linux服务器(系统Ubuntu Server),但是毕竟是ARM CPU,而且黄金内存,开不了几个虚拟机(加内存不划算),所以组装…...
计算机网络中的网络层:架构、功能与重要性
一、网络层概述 在计算机网络的分层模型中,网络层(Network Layer)位于 数据链路层 之上,传输层 之下。网络层的主要任务是处理数据包的路由选择、转发以及分段,使得信息能够从源设备传送到目标设备。它还通过 IP协议&…...
Transformer系列(一):NLP中放弃使用循环神经网络架构
NLP中放弃使用循环神经网络架构 一、符号表示与概念基础二、循环神经网络1. 依赖序列索引存在的并行计算问题2. 线性交互距离 三、总结 该系列笔记阐述了自然语言处理(NLP)中不再采用循环架构(recurrent architectures)的原因&…...
(学习总结34)Linux 库制作与原理
Linux 库制作与原理 库的概念静态库操作归档文件命令 ar静态库制作静态库使用 动态库动态库制作动态库使用与运行搜索路径问题解决方案方案2:建立同名软链接方案3:使用环境变量 LD_LIBRARY_PATH方案4:ldconfig 方案 使用外部库目标文件ELF 文…...
【QT】 QT中的列表框-横向列表框-树状列表框-表格列表框
QT中的列表框-横向列表框-树状列表框-表格列表框 1.横向列表框(1)主要方法(2)信号(3) 示例代码1:(4) 现象:(5) 示例代码2:加载目录项在横向列表框显示(6) 现象: 2.树状列表框 QTreeWidget(1)使用思路(2)信号(3)常用的接口函数(4) 示例代码&am…...
使用DeepSeek的AIGC的内容创作者,如何看待陈望道先生所著的《修辞学发凡》?
目录 1.从修辞手法的运用角度 2.从语言风格的塑造角度 3.从提高创作效率角度 4.从文化传承与创新角度 大家好这里是AIWritePaper官方账号,官网👉AIWritePaper~ 《修辞学发凡》是陈望道 1932 年出版的中国第一部系统的修辞学著作,科学地总…...