Java【多线程】(7)常见的锁策略
目录
1.前言
2.正文
2.1悲观锁和乐观锁
2.2重量级锁和轻量级锁
2.3挂起等待锁和自旋锁
2.4互斥锁与读写锁
2.5可重入锁与不可重入锁
2.6公平锁与不公平锁
2.7synchronized优化
2.7.1锁升级
2.7.2锁消除
2.7.3锁粗化
3.小结
1.前言
哈喽大家好,今天来给大家分享Java多线程中常见的锁策略,锁策略不是和Java强相关,但凡涉及到并发编程涉及到锁都会涉及锁策略,概念较多但都很重要,废话不多说让我们开始吧。
2.正文
首先在这里声明一点:以下讲的各种锁,不是针对某一种具体的锁,而是某个具体锁具有“悲观"特性或者“乐观”等特性~~
2.1悲观锁和乐观锁
悲观锁:
定义:假设并发冲突一定会发生,因此在操作数据前先加锁,确保同一时刻只有一个线程能访问资源。
特点:强一致性,但性能开销大。
乐观锁:
定义:假设并发冲突很少发生,操作数据时不加锁,只在提交修改时检查是否被其他线程修改过。
特点:高性能,但可能需重试。
悲观锁的现实场景:
你去银行取钱,柜员会说:"稍等,我先锁上保险箱再给你拿钱。"
为什么?银行默认你会和别人争抢取钱这个操作,必须锁住资源。
乐观锁的现实场景:
你和同事改同一份Docs,直接编辑,保存时系统提示:"有冲突,请解决。"
为什么?默认你们不会同时改同一段落,冲突了再处理。
根本区别在于对接下来锁竞争的是否激烈。
对比维度 悲观锁 乐观锁 默认态度 "肯定会有人抢,先锁再说!" "应该没人抢,冲突了再说~" 实现方式 synchronized
、ReentrantLock
版本号、CAS(如 AtomicInteger
)性能开销 高(上下文切换、阻塞) 低(无阻塞,可能重试) 适用场景 写多读少(如支付、转账) 读多写少(如商品库存、点赞计数) 失败处理 线程阻塞等待 回滚或自动重试
2.2重量级锁和轻量级锁
重量级锁:
定义:依赖操作系统内核的互斥量(Mutex Lock)实现的锁机制,线程竞争时会直接进入阻塞状态,由操作系统负责线程调度。
特点:功能完备(支持公平性、超时等),但性能开销大(涉及用户态到内核态的切换)。
轻量级锁:
定义:基于CAS(Compare-And-Swap)自旋实现的锁机制,线程通过循环尝试获取锁,避免直接进入阻塞状态。
特点:性能高(无系统调用),但长时间自旋会浪费CPU资源。
重量级锁的现实场景:
你去医院挂号,发现窗口排队的人很多,直接去休息区睡觉(线程阻塞),等护士叫号(操作系统唤醒)。
为什么?因为你知道要等很久,不如让出资源。
轻量级锁的现实场景:
你在便利店排队结账,发现前面只有一个人,于是站在原地不停张望(自旋),等对方结束立马抢位置。
为什么?因为等待时间短,不值得去找座位。
- 重量级锁,当悲观的场景下,此时就要付出更多的代价。(更低效)
- 轻量级锁,应对乐观的场景,此时付出的代价就会更小。(更高效)
对比维度 重量级锁 轻量级锁 实现原理 通过操作系统内核的互斥量(Mutex) 用户态的CAS自旋(如 AtomicInteger
)线程状态 阻塞(挂起) 运行中(自旋等待) 性能开销 高(上下文切换约1-10μs) 低(自旋耗时约0.1-1ns/次) 适用场景 高竞争、长临界区 低竞争、短临界区 失败处理 线程进入等待队列 继续自旋或升级为重量级锁
2.3挂起等待锁和自旋锁
挂起等待锁就是重量级锁的典型实现,而自旋锁就是轻量级锁的典型实现。
挂起等待锁(阻塞锁):
定义:当线程获取锁失败时,立即释放CPU资源,进入阻塞状态(挂起),等待被唤醒
核心机制:依赖操作系统调度,涉及线程上下文切换
典型实现:Java的
synchronized
在重量级锁状态、ReentrantLock.lock()
自旋锁:
定义:当线程获取锁失败时,不放弃CPU,而是循环重试(自旋),直到成功获取锁
核心机制:通过CPU空转(忙等待)避免上下文切换
典型实现:Java的
AtomicInteger
CAS操作、ReentrantLock.tryLock()
自旋版本(以后会详细讲解Java中的CAS)
挂起等待锁场景:
你去热门餐厅取号,服务员说:"现在没位,去旁边商场逛2小时再回来"(线程挂起)
为什么合理:等待时间长时,干等着(自旋)反而浪费精力
自旋锁场景:
你在便利店排队,收银员说:"稍等1分钟马上好",你选择站着玩手机等待(自旋)
为什么合理:短暂等待时,来回走动(上下文切换)更耗能
对比维度 挂起等待锁 自旋锁 等待机制 立即释放CPU进入阻塞状态 保持CPU占用循环检测 系统开销 高(上下文切换约1-10μs) 低(但浪费CPU周期) 实现复杂度 高(需OS支持线程调度) 低(CAS即可实现) 适用场景 锁持有时间长(>1ms) 锁持有时间短(<1μs) 线程状态 BLOCKED/WATING RUNNABLE 公平性 通常可实现公平 通常是非公平的 典型应用 数据库事务、文件IO 计数器、状态标志
2.4互斥锁与读写锁
分析下这个读写锁:多个线程读取一个数据,是本身就线程安全的。多个线程读取,一个线程修改,肯定会涉及到线程安全问题。如果你把读和写都加上普通的互斥锁,意味着锁冲突将会非常严重,读锁和读锁之间不互斥,读锁和写锁互斥,写锁和写锁之间也互斥。于是乎读写所的存在,保证线程安全的前提下,降低锁冲突概率提高效率。
互斥锁(Mutex Lock):
定义:独占锁,同一时刻只允许一个线程访问共享资源
特点:强排他性,读/写操作同等对待
典型实现:Java的
synchronized
、ReentrantLock
读写锁(ReadWrite Lock):
定义:分离锁,将读操作和写操作区别对待
特点:允许多个读线程并发,写线程独占
典型实现:Java的
ReentrantReadWriteLock
互斥锁场景:
图书馆自习室规则:"每次只允许一人进入,无论你是看书(读)还是做笔记(写)"
结果:即使多人只想看书,也得排队轮流进
读写锁场景:
改进后的规则:"看书的人可以一起进,但做笔记的人必须单独使用房间"
结果:读书效率提升,写作时仍保证独占
对比维度 互斥锁 读写锁 并发粒度 完全互斥 读读并发,读写/写写互斥 吞吐量 低(所有操作串行) 高(读操作可并行) 实现复杂度 简单 复杂(需维护读/写状态) 适用场景 读写操作耗时相近 读多写少(≥5:1) 线程饥饿风险 无 写线程可能被读线程长期阻塞 锁升级 不支持 读锁不能升级为写锁(会死锁) 公平性 可公平/非公平 可公平/非公平
2.5可重入锁与不可重入锁
之前文章中讲解过这里不过多展开了喔~简单总结~
可重入锁(Reentrant Lock):
定义:同一个线程可以多次获取同一把锁,锁会维护一个持有计数(hold count)
关键特性:防止线程自己造成死锁
典型实现:Java的
synchronized
、ReentrantLock
不可重入锁(Non-reentrant Lock):
定义:线程获取锁后,再次尝试获取会立即阻塞/失败
关键特性:严格线性获取锁
典型实现:早期的简单锁实现、某些特定场景的自旋锁
可重入锁场景:
你家大门装了智能锁,你(线程)进入时:
- 第一次进门:验证指纹(获取锁)
- 进卧室时:不再验证(重入计数+1)
- 离开卧室:不真正锁门(计数-1)
- 最终出门:才真正上锁(计数归零)
不可重入锁场景:
老式钥匙锁的尴尬情况:
- 你进门后锁上门(获取锁)
- 想进里屋时发现需要钥匙(再次获取锁)
- 钥匙插在外门锁上(死锁形成)
- 最终困在门厅里(线程阻塞)
对比维度 可重入锁 不可重入锁 死锁预防 避免同一线程自我死锁 可能因递归调用导致自我死锁 实现复杂度 高(需维护线程ID和计数) 低(只需布尔状态) 性能开销 略高(计数器操作) 略低 适用场景 递归调用、回调函数 简单线性流程 锁释放 必须完全释放(计数归零) 单次解锁即释放 典型应用 Java同步机制、数据库事务 某些内核锁、特殊优化场景
2.6公平锁与不公平锁
公平锁(Fair Lock):
定义:按照线程请求锁的先后顺序分配锁,遵循FIFO(先进先出)原则
特点:避免线程饥饿,保证公平性
实现方式:通过队列维护等待线程(如
ReentrantLock(true)
)非公平锁(Non-fair Lock):
定义:允许线程插队获取锁,不保证请求顺序
特点:吞吐量高,但可能导致线程饥饿
实现方式:直接尝试CAS获取锁(如
synchronized
和ReentrantLock()
默认模式)
公平锁场景:
银行VIP窗口叫号系统:"请A001号到3号窗口"(严格按取号顺序服务)
优点:先来的人一定能先办业务
缺点:即使窗口空闲,也必须叫号
非公平锁场景:
地铁早高峰排队:"车门一开,所有人挤着上车"(谁快谁上)
优点:车厢利用率高(减少空置时间)
缺点:可能有人永远挤不上去
对比维度 公平锁 非公平锁 排队机制 严格FIFO 允许插队(新线程可直接竞争) 吞吐量 较低(约降低30%) 较高 线程饥饿 不会发生 可能发生 实现复杂度 高(需维护等待队列) 低(直接CAS) 响应时间 稳定但较长 不稳定(可能极快或极慢) 适用场景 交易系统、计费系统 高并发缓存、计数器 JVM实现 ReentrantLock(true)
synchronized
、ReentrantLock()
公平锁:
public class FairLockDemo {private static final ReentrantLock lock = new ReentrantLock(true); // 公平模式public static void main(String[] args) {for (int i = 0; i < 3; i++) {new Thread(() -> {lock.lock();try {System.out.println(Thread.currentThread().getName() + "获取锁");} finally {lock.unlock();}}, "Thread-" + i).start();}} } // 输出保证按线程启动顺序获取锁
非公平锁:
public class NonFairDemo {private static final ReentrantLock lock = new ReentrantLock(); // 默认非公平public static void main(String[] args) {// 先让主线程持有锁lock.lock();new Thread(() -> {System.out.println("子线程尝试获取锁");lock.lock(); // 这里会插队!System.out.println("子线程获取成功");lock.unlock();}).start();Thread.sleep(100); // 确保子线程启动System.out.println("主线程释放锁");lock.unlock(); // 释放后子线程可能抢到,即使有其他等待线程} }
2.7synchronized优化
2.7.1锁升级
JVM根据竞争情况,动态调整synchronized
的锁状态,从低开销到高开销逐步升级,避免一刀切使用重量级锁。 JVM没有提供锁降级。
graph LRA[无锁] -->|首次获取| B[偏向锁]B -->|有竞争| C[轻量级锁]C -->|竞争加剧| D[重量级锁]
偏向锁(Biased Locking)
场景:单线程反复访问同步块
原理:在对象头记录线程ID(无需CAS)
轻量级锁(Thin Lock)
场景:多线程交替执行(无真正竞争)
原理:
栈帧中创建Lock Record
通过CAS将对象头指向Lock Record
重量级锁(Heavyweight Lock)
场景:高并发竞争
原理:通过
ObjectMonitor
实现开销:上下文切换约1-10μs
补充以下何为偏向锁:
刚一上来,不是真加锁, 而是只是简单做一个标记,进行synchronized。这个标记,非常轻量, 相比于加锁解锁来说,效率高很多~如果没有其他线程来竞争这个锁,最终当前线程执行到解锁代码,也就只是简单清除上标记即可~~(不涉及真加锁,真解锁)如果有其他线程来竞争,就抢先一步,在另一个线程拿到锁之前,抢先拿到锁真假锁了,偏向锁 =>轻量级锁,其他线程只能阻塞等待。
2.7.2锁消除
这也是编译器优化的一种体现。
概念:编译器会判定,当前这个代码逻辑是否真的需要加锁,如果确实不需要加锁,但是你写了 synchronized,,就会自动把synchronized给去掉,像一些判定不清楚的情况,不会触发锁消除。
如果到处有synchronized,意味着优化机制,只能把其中一部分,他能明确判定的给优化掉,还会有很多不应该使用, 但是编译器也优化不调。
2.7.3锁粗化
概念:
将相邻的多个细粒度锁合并为单个大锁,减少锁申请/释放开销。(加锁和解锁之间,包含的代码越多,就认为锁的粒度就越粗)触发场景:
// 原始代码 for (int i = 0; i < 100; i++) {synchronized(obj) { // 每次循环都加锁doSomething();} }// 优化后等效代码 synchronized(obj) { // 合并为单个锁for (int i = 0; i < 100; i++) {doSomething();} }
以上三种做个总结:
优化手段 | 适用场景 | 性能提升幅度 | 实现层级 |
---|---|---|---|
锁升级 | 所有synchronized 场景 | 10-100倍 | JVM运行时 |
锁消除 | 线程私有对象 | 2-5倍 | JIT编译期 |
锁粗化 | 密集短锁操作 | 1.5-3倍 | 字节码优化阶段 |
3.小结
今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!
相关文章:
Java【多线程】(7)常见的锁策略
目录 1.前言 2.正文 2.1悲观锁和乐观锁 2.2重量级锁和轻量级锁 2.3挂起等待锁和自旋锁 2.4互斥锁与读写锁 2.5可重入锁与不可重入锁 2.6公平锁与不公平锁 2.7synchronized优化 2.7.1锁升级 2.7.2锁消除 2.7.3锁粗化 3.小结 1.前言 哈喽大家好,今天来给…...
Android Compose 中获取和使用 Context 的完整指南
在 Android Jetpack Compose 中,虽然大多数 UI 组件不再需要直接使用 Context,但有时你仍然需要访问它来执行一些 Android 平台特定的操作。以下是几种在 Compose 中获取和使用 Context 的方法: 1. 使用 LocalContext 这是 Compose 中最常用…...
车载通信基础 --- 解密公开密钥基础设施(PKI)
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁&am…...
深度强化学习基础 1:以狗狗学习握手为例
强化学习共同框架 在这个狗狗学习握手的场景中,强化学习的各个要素可以这样理解: 状态s(state): 狗狗所处的环境状况,比如主人伸出手掌的姿势、狗狗自身的姿势、周围的环境等。状态s描述了狗狗在特定时刻所感知到的环境信息。 动作a(action): 狗狗可以…...
【Kafka基础】topics命令行操作大全:高级命令解析(2)
1 强制删除主题 /export/home/kafka_zk/kafka_2.13-2.7.1/bin/kafka-topics.sh --delete \--zookeeper 192.168.10.33:2181 \--topic mytopic \--if-exists 参数说明: --zookeeper:直接连接Zookeeper删除(旧版本方式)--if-exists&…...
【redis】简介及在springboot中的使用
redis简介 基本概念 Redis,英文全称是Remote Dictionary Server(远程字典服务),是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 与MySQL数据库不…...
Windwos的DNS解析命令nslookup
nslookup 解析dns的命令 有两种使用方式,交互式&命令行方式。 交互式 C:\Users\Administrator>nslookup 默认服务器: UnKnown Address: fe80::52f7:edff:fe28:35de> www.baidu.com 服务器: UnKnown Address: fe80::52f7:edff:fe28:35de非权威应答:…...
Vue.js 实现下载模板和导入模板、数据比对功能核心实现。
在前端开发中,数据比对是一个常见需求,尤其在资产管理等场景中。本文将基于 Vue.js 和 Element UI,通过一个简化的代码示例,展示如何实现“新建比对”和“开始比对”功能的核心部分。 一、功能简介 我们将聚焦两个核心功能&…...
通过世界排名第一的免费开源ERP,构建富有弹性的智能供应链
概述 现行供应链模式的结构性弱点凸显了对整个行业进行重塑的必要性。正确策略和支持可以帮助您重塑供应链,降低成本,实现业务转型。开源智造(OSCG)所推出的Odoo免费开源ERP解决方案,将供应链转化为具有快速响应能力的…...
自动驾驶数据闭环中的MLOps实践:Kubernetes、Kubeflow与PyTorch的协同应用
目录 1. 引言 2. 系统架构与技术栈 2.1 Kubernetes:弹性可伸缩的计算资源池 2.2 Kubeflow:端到端的MLOps工作流 2.3 PyTorch分布式训练:高效的模型训练引擎 3. 增强型数据处理技术 3.1 联邦学习聚合 3.2 在线学习更新 3.3 角落案例挖…...
如何在Linux中更改主机名?修改主机最新方法
hostname是一个Linux操作系统的常用功能,允许识别服务器, 这可用于容易地确定两个服务器之间的差异。 除了服务器的个人识别,主机名与大多数网络进程一起使用,其他应用程序也可能依赖于此,本期将指导大家如何在Linux中…...
分盘,内网
分盘 查看创建分区 # 查看磁盘信息(确认目标磁盘,如/dev/sda) lsblkfdisk -l# 启动fdisk工具(需root权限) sudo fdisk /dev/sda# 步骤1:删除旧分区表(谨慎操作!) Comma…...
SQL122 删除索引
alter table examination_info drop index uniq_idx_exam_id; alter table examination_info drop index full_idx_tag; 描述 请删除examination_info表上的唯一索引uniq_idx_exam_id和全文索引full_idx_tag。 后台会通过 SHOW INDEX FROM examination_info 来对比输出结果。…...
【SQL】子查询详解(附例题)
子查询 子查询的表示形式为:(SELECT 语句),它是IN、EXISTS等运算符的运算数,它也出现于FROM子句和VALUES子句。包含子查询的查询叫做嵌套查询。嵌套查询分为相关嵌套查询和不想关嵌套查询 WHERE子句中的子查询 比较运算符 子查询的结果是…...
AI和传统命理的结合
deepseek的火热 也带来了AI命理学的爆火 1. 精准解析:AI加持,数据驱动 通过先进的人工智能算法,我们对海量的传统命理知识进行了深度学习和整合。无论是八字排盘、紫微斗数,还是风水布局、生肖运势,AI都能根据您的个…...
Java设计模式之抽象工厂模式:从入门到架构级实践
设计模式是构建高质量软件的基石,而抽象工厂模式作为创建型模式的代表,不仅解决了对象创建的问题,更在架构设计中扮演着关键角色。本文将从基础到高阶、从单机到分布式,全面剖析抽象工厂模式的应用场景与实战技巧。 一、从问题出发…...
摄像头模块对焦方式的类型
摄像头模块的对焦方式直接影响成像清晰度和使用场景适应性,不同技术各有其优缺点。以下是常见对焦方式及其原理、特点和应用场景的详细说明: 1. 固定对焦(Fixed Focus) 原理:镜头固定在特定距离(…...
九屏图分析法以手机为例
九屏图的两种视角 时间九屏图:关注系统的时间演化(过去、现在、未来),强调技术或产品的生命周期。空间九屏图:关注系统的层次结构(子系统、本系统、超系统࿰…...
【模板】前缀和
链接:【模板】前缀和 题目描述 给定一个长度为n的数组a1,a2,....ana_1, a_2,....a_na1,a2,....an. 接下来有q次查询, 每次查询有两个参数l, r. 对于每个询问, 请输出alal1....ara_la_{l1}....a_ralal1....ar 输入描述: 第一行包含两个整数n和q. 第…...
微信小程序多线程的使用
微信小程序的多线程主要通过 Worker 实现,用于处理复杂计算任务以避免阻塞主线程。以下是完整的使用指南和最佳实践: 一、Worker 核心机制 运行环境隔离 主线程与 Worker 线程内存不共享通信通过 postMessage 完成(数据拷贝而非共享ÿ…...
FPGA设计职位介绍|如何成为一名合格的数字前端设计工程师?
近年来FPGA行业持续升温,随着国产替代浪潮的加快推进,国家对可重构计算、边缘计算、自主可控等领域的扶持力度不断加大,FPGA作为灵活性高、可编程性强的重要芯片种类,在人工智能、通信、工业控制等应用中广受青睐。FPGA人才长期紧…...
Shell 基础
刷题: 思维导图: #include <stdio.h> // 手动定义32位有符号整数的范围 #define INT_MAX 2147483647 #define INT_MIN (-2147483647 - 1) int reverse(int x) { int rev 0; // 初始化反转后的数字为0 while (x ! 0) { // 当x不为0时ÿ…...
软件信息安全性测试如何进行?有哪些注意事项?
随着信息技术的高速发展,软件已经成为我们生活和工作中不可或缺的一部分。然而,随着软件产品的广泛普及,软件信息安全性问题也日益凸显,因此软件信息安全性测试必不可少。那么软件信息安全性测试应如何进行呢?在进行过程中又有哪…...
ragflow开启https访问:浏览器将自签证书添加到受信任的根证书颁发机构 ,当证书过期,还需要添加吗?
核心机制解析 信任链原理: 当您将自签名证书添加到"受信任的根证书颁发机构"后,系统会永久信任该证书的颁发者身份但证书本身的有效期和密钥匹配仍需验证证书更新的两种情况: 相同密钥续期:如果新证书使用相同的密钥对,浏览器通常会保持信任重新生成密钥:如果执…...
ragflow开启https访问:自签证书到期了,如何自动生成新证书
自动生成和更新自签名证书的方案 对于使用公网IP和自签名证书的RagFlow服务,要实现证书的自动生成和更新,可以采用以下方案: 方案一:使用脚本自动更新(推荐) 1. 创建自动更新脚本 在服务器上创建 ./docker/nginx/auto_renew_cert.sh 文件: #!/bin/bash# 证书路径 C…...
LLM面试题八
推荐算法工程师面试题 二分类的分类损失函数? 二分类的分类损失函数一般采用交叉熵(Cross Entropy)损失函数,即CE损失函数。二分类问题的CE损失函数可以写成:其中,y是真实标签,p是预测标签,取值为0或1。 …...
小行星轨道预测是怎么做的?从天文观测到 AI 模型的完整路径
目录 ☄️ 小行星轨道预测是怎么做的?从天文观测到 AI 模型的完整路径 🌌 一、什么是小行星轨道预测? 🔭 二、观测数据从哪里来? 🧮 三、经典动力学方法:数值积分 🤖 四、现代方…...
华为OD机试2025A卷 - 正整数到excel编号之间的转换(Java Python JS C++ C )
最新华为OD机试 真题目录:点击查看目录 华为OD面试真题精选:点击立即查看 题目描述 用过 excel 的都知道excel的列编号是这样的: a b c … z aa ab ac … az ba bb bc … yz za zb zc … zz aaa aab aac … 分别代表以下编号: 1 2 3 … 26 27 28 29 … 52 53 54 55…...
2024年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析
2024年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析 全国大学生数学建模竞赛(China Undergraduate Mathematical Contest in Modeling)是国家教委高教司和中国工业与应用数学学会共同主办的面向全国大学生的群众性科技活动,目的在于激…...
Vue3 实现进度条组件
样式如下,代码如下 <script setup> import { computed, defineEmits, defineProps, onMounted, ref, watch } from vue// 定义 props const props defineProps({// 初始百分比initialPercentage: {type: Number,default: 0,}, })// 定义 emits const emits…...
I²S协议概述与信号线说明
IIS协议概述 IS(Inter-IC Sound)协议,又称 IIS(Inter-IC Sound),是一种专门用于数字音频数据传输的串行总线标准,由飞利浦(Philips)公司提出。该协议通常用于微控制器…...
Redis 面经
1、说说什么是 Redis? Redis 是 Remote Dictionary Service 三个单词中加粗字母的组合,是一种基于键值对的 NoSQL 数据库。但比一般的键值对,比如 HashMap 强大的多,Redis 中的 value 支持 string、hash、 list、set、zset、Bitmaps、Hyper…...
设计模式 四、行为设计模式(1)
在设计模式的世界里,23种经典设计模式通常被分为三大类:创建型、结构型和行为型。创建型设计模式关注对象创建的问题,结构性设计模式关注于类或对象的组合和组装的问题,行为型设计模式则主要关注于类或对象之间的交互问题。 行为设…...
Python错误分析与调试
在Python编程的过程中,我们难免会遇到各种各样的错误,而有效地分析和调试这些错误,能让我们的代码快速恢复正常运行,今天就来和大家聊聊Python中错误分析与调试的相关内容。 错误分析 Python中的错误大致可以分为语法错误和逻…...
vue实现大转盘抽奖
用vue实现一个简单的大转盘抽奖案例 大转盘 一 转盘布局 <div class"lucky-wheel-content"><div class"lucky-wheel-prize" :style"wheelStyle" :class"isStart ? animated-icon : "transitionend"onWheelTransitionE…...
《从零搭建Vue3项目实战》(AI辅助搭建Vue3+ElemntPlus后台管理项目)零基础入门系列第二篇:项目创建和初始化
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 《从零搭建Vue3项目实战》(AI辅助…...
yum拒绝连接
YUM 拒绝连接的解决方案 当遇到 yum 无法连接的问题时,通常可以通过更换为更稳定的镜像源来解决问题。以下是具体的解决方法: 更换为阿里云源 如果当前的 yum 配置文件存在问题或网络不稳定,可以尝试将其替换为阿里云的镜像源。 备份原始配…...
信息学奥赛一本通 1861:【10NOIP提高组】关押罪犯 | 洛谷 P1525 [NOIP 2010 提高组] 关押罪犯
【题目链接】 ybt 1861:【10NOIP提高组】关押罪犯 洛谷 P1525 [NOIP 2010 提高组] 关押罪犯 【题目考点】 1. 图论:二分图 2. 二分答案 3. 种类并查集 【解题思路】 解法1:种类并查集 一个囚犯是一个顶点,一个囚犯对可以看…...
代码随想录算法训练营第十一天
LeetCode/卡码网题目: 144. 二叉树的前序遍历94. 二叉树的中序遍历145. 二叉树的后序遍历102. 二叉树的层序遍历107.二叉树的层次遍历II199. 二叉树的右视图637. 二叉树的层平均值429. N 叉树的层序遍历515. 在每个树行中找最大值116. 填充每个节点的下一个右侧节点指针117. 填…...
浅谈进程的就绪状态与挂起状态
就绪状态 进程获得除 CPU 之外的所需资源,一旦得到 CPU 就可以立即运行,不能运行的原因是还是因为 CPU 的资源太少,只能等待分配 CPU 资源。在系统中,处于就绪状态的进程可能有多个,通常是将它们组成一个进程就绪队列…...
37、web前端开发之Vue3保姆教程(一)
一、课程简介 本课程旨在帮助学员从零基础逐步掌握Web前端开发的核心技术,涵盖当前前端开发中的关键工具和框架。课程内容包括: Vue 3:主流前端框架,支持组件化开发和响应式数据管理,帮助学员高效构建现代Web应用。TypeScript:增强版JavaScript,提供静态类型支持,提高…...
cenos7升级gcc 9.3和Qt5.15版本教程
cenos7升级gcc 9.3和Qt5.15版本教程 文章目录 cenos7升级gcc 9.3和Qt5.15版本教程0、背景1、现状2、目标和思路3、升级前环境准备3.1 虚拟机联网配置3.2 镜像设置 4、升级gcc 9.35 升级Qt6 测试验证7 总结 0、背景 之前编码的环境一直是“拿来主义”,拷贝现成的虚拟…...
Scala总结(七)
集合(二) 数组 不可变数组与可变数组的转换 arr1.toBuffer //不可变数组转可变数组 arr2.toArray //可变数组转不可变数组 arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化arr1.toBuffer 返回结果才是一个可变数组ÿ…...
linux 使用 usermod 授权 普通用户 属组权限
之前写过这篇文章 linux 普通用户 使用 docker 只不过是使用 root 用户编辑 /etc/group用户所属组文件的方式 今天带来一种 usermod 命令行方式 以下3步,在root用户下操作 第一步,先创建一个普通用户测试使用 useradd miniuser第二步,授权到…...
Redis持久化
Redis持久化 一.认识持久化1.简单介绍2.持久化策略 二.RDB1.快照2."定期"fork 3.RDB演示(1)手动执行save&bgsave触发一次生成快照(2)插入key,不手动执行bgsave(3)执行bgsave后,新旧文件的替换(4)通过配置自动生成rdb快照(5)rdb文件内容被故…...
什么是 k8s 的 Taints(污点) 和 Tolerations(容忍度)
什么是 k8s 的 Taints(污点) 和 Tolerations(容忍度) 在 Kubernetes(K8s)中,Taints(污点)和 Tolerations(容忍度)用于影响 Pod 调度到节点的行为…...
是德科技KEYSIGHT校准件85039B
是德科技KEYSIGHT校准件85039B 是德科技KEYSIGHT校准件85039B 85039B Agilent | 85039B|校准件|网络分析仪校准件|3GHz|75欧|N型 品牌: 安捷伦 | Agilent | 惠普 | HP 主要技术指标 DC to 3GHz frequency range 主要描述 常用型号: 一、频谱分析仪或…...
以UE5第三方插件库为基础,编写自己的第三方库插件,并且能够在运行时复制.dll
首先,创建一个空白的C 项目,创建第三方插件库。如下图所示 编译自己的.Dll 和.lib 库,打开.sln 如下图 ExampleLibrary.h 的代码如下 #if defined _WIN32 || defined _WIN64 #define EXAMPLELIBRARY_IMPORT __declspec(dllimport) #elif d…...
StarRocks执行原理与SQL性能优化策略探索
https://zhuanlan.zhihu.com/p/15707561363 聚合优化实践 -- 通过count group by 优化 count distinct数据倾斜问题 除了前面所说的聚合度会对分组聚合造成比较大的影响外,我们还要考虑一个点,即数据倾斜问题。 背景: 如下为最初的用户计算uv的SQL SE…...
Java全栈面试宝典:JMM内存模型与Spring自动装配深度解析
目录 一、Java内存模型(JMM)核心原理 🔥 问题8:happens-before原则全景解析 JMM内存架构图 happens-before八大规则 线程安全验证案例 🔥 问题9:JMM解决可见性的三大武器 可见性保障机制 volatile双…...