多线程 - 线程安全 2 -- > 死锁问题
目录
小结复习:
线程安全:
如何解决线程安全问题?
synchronized
“死锁”
死锁的三种经典场景:
1. 一个线程,一把锁。
2.两个线程,两把锁。
3. N 个线程 M 把锁
完!
小结复习:
线程安全:
1. 【根本原因】 线程的随机调度,抢占式实行(罪魁祸首,万恶之源),多个线程执行的顺序,存在诸多变数,我们要做的就是需要保证任何一种变数下,执行结果都是正确的,无 bug 的。
2. 多个线程同时修改同一个变量。
3. 修改操作不是原子的。count++ 本质上是 3 个指令,load,add,save...类似的 +=,-= 也是非原子的,但是 = 这种操作,一般是原子的。
4. 内存可见性
5. 指令重排序
如何解决线程安全问题?
加锁 ==》 synchronized 关键字,(锁对象),锁对象随便放一个 Object 都行,需要关注两个线程是否是针对同一个对象加锁。{代码块},Java 代码进入代码块,加锁,离开代码块,解锁。
synchronized 修饰普通方法,相当于给 this 加锁(锁对象 this),synchronized 修饰静态方法,相当于给类对象加锁。
synchronized
synchronized 加锁的效果,也可以称为”互斥性“。synchronized 还有一些其他的特性。
举一个例子:
上述例子,是否可以正常运行,打印 hello 呢? absolutely,可以正常打印 hello。
背后的运行过程:在第一个 synchronized 中,针对 locker 进行加锁,这里的加锁是可以顺利获取到的。下一个 synchronized 中,直观上感觉,这个加锁,应该不能成功呀,此时的 locker 对象处于一句加锁的状态,这个时候,如果要是再尝试对 locker 进行加锁,不应该会出现“阻塞”的情况吗?
但程序又是可以正常运行的呀,关键的问题是,这两次加锁,其实是在同一个线程中进行的。
当前由于是同一个进程,此时锁对象,是知道,第二次加锁的线程,就是持有锁的线程,第二次操作,就可以直接放行通过,不会出现阻塞。
这个特性,就被称为 “可重入性”,使用可重入锁,就可以避免上述代码出现死锁的情况。
那这种双重加锁有什么应用场景吗? ==》 根本没有,这种情况本身就是代码有问题,没有应用场景,但是我们写代码的时候,很容易一不小心,就写出这种双重加锁的效果,可重入锁,就是为例防止,我们在“不小心”中,引入问题,即,就算我们不小心写了双重加锁,也不至于出现死锁情况。
如下:
直观上看,每个地方都只是加了一次锁,但是由于复杂的调用关系,就可能导致,加锁重复了。
那这种情况,就是默认把多个锁看作是一个锁吗? 不完全是。
如上图,红色圈 1,此时是真正的加锁,同时 synchronized 中的计数器会 +1(初始情况为0, +1 之后变成了1,说明当前这个对象被该线程加锁了)同时记录线程是谁。
红色圈 2,是第二次加锁的时候,发现加锁线程和持有锁的线程是同一个线程,则计数器++,没有别的操作了,如果不是同一个线程,则会发生阻塞。
蓝色圈 3,把计数器 -1,2 =》 1,由于计数器不为0,不会真的解锁。
蓝色圈 4,再把计数器 -1,1 =》 0,此时计数器归零,真正进行解锁了。
对如可重入锁来说,内部会持有两个信息 ==》 1. 当前这个锁是被那个线程所持有的 2.加锁次数的计数器。
注意,虽然有两个 synchronized,但是,只有一个锁对象,只有一把锁!
总结:
如果对一个线程,不小心使得有多个 synchronized 的情况,则会在最外层的 { 进行加锁,在最外层的 } 进行解锁。
这样,即使上述是 synchronized 嵌套 10 层或者 8 层的,也不会使得解锁操作混乱,并且始终能够保证在正确的时机解锁。
此处的计数器,是真正用来识别解锁时机的关键要点,这个源码是在 JVM 中利用 C++ 代码实现的,在 IDEA 中看不到。
“死锁”
死锁,是多线程代码中的一类经典问题,加锁是能解决线程的安全问题,但如果加锁方式不当,就有可能产生死锁!!!
死锁的三种经典场景:
1. 一个线程,一把锁。
就像上面的场景,如果上面的锁是不可重入锁,并且一个线程对这把锁,加锁两次,就会出现死锁现象。(钥匙锁在屋子里了)
2.两个线程,两把锁。
线程 1 获得到锁 A,线程 2 获得到锁 B,接下来,1 尝试获取锁 B,2尝试获取锁 A,就同样出现死锁了!!!一旦出现死锁,线程就“卡住了”,无法继续工作,死锁,是属于进程中最严重的一类 bug !!!
示例如下:
运行上述进程,我们可以使用 jconsole 来观察
Thread - 0 被 Thread - 1锁住了,状态为 BLOCKED
Thread - 1 被 Thread - 0锁住了,状态为 BLOCKED
3. N 个线程 M 把锁
这种情况,就会牵扯到一个被称为 “哲学家就餐” 的问题。
假设有五个哲学家围坐在一张圆桌旁,他们的生活方式就是思考和进餐。圆桌上有五根筷子,每两个哲学家之间放一根。哲学家在思考时不需要任何资源,而当他们进餐时,必须同时拿起左右两边的筷子。如果筷子已经被其他哲学家占用,那么该哲学家必须等待,直到筷子可用。
如果某个哲学家,在吃中间的面条的过程中,旁边的两位哲学家,就需要阻塞等待(五个筷子,就相当于五把锁,每个哲学家,就是一个线程)。当线程拿到锁的时候,就会一直持有,除非他吃完了,主动放下筷子,(哲学家都是有身份的人),其他哲学家不能硬抢。
虽然筷子的数量并不充裕,但其实也还还好,每个哲学家,除了吃面条之外,还要做一件事,“思考人生”,在做这件事的时候,哲学家是会放下筷子的。
由于每个哲学家,什么时候吃面条,什么时思考人生,这个事情是不确定的(随即调度),绝大部分情况下,上述模型都是可以正常工作的。
但是,有一些极端的特殊情况,是无法正常工作的。
假设同一时刻,所有的哲学家,都想要吃面条,同时拿起了左手的筷子,这个时候,他们继续尝试拿起右边的筷子,唉,发现拿不起来了,右边的筷子被别人给拿着了!!!
此时,由于所有的哲学家,都不想放下已经拿起来的筷子,就要等待旁边的人放下筷子...没有人能吃到面,也就没有人释放,也就形成死锁了。
解决死锁问题,方案有很多种:
先解释一下,产生死锁的 四 个必要条件:
1. 互斥使用,获得锁的过程是互斥的。即,一个线程拿到了这把锁,另一个线程如果也想获取,就需要阻塞等待。
2. 不可抢占。一个线程拿到锁之后,就只能主动解锁,不能让别的线程,强行把锁抢走。
3. 请求保持。一个线程拿到锁 A 之后,在持有 A 的前提下,尝试获取 B。
4. 循环等待 / 环路等待。
那如何解决死锁问题呢?核心思路,就是破坏上述的 四 必要条件呗,且只要能破坏其中一个,就可以解决死锁问题。
1.互斥使用。这是锁的最基本特性,我们不太好破坏。
2. 不可抢占。同样的,这也是锁的最基本特性,同样不好破坏。
3. 请求保持。 这个操作是取决于代码结构的,不一定可以破坏,要看实际的代码需求。
4.循环等待 / 环路等待。 这个是代码结构中,且是最容易破坏的。
我们可以指定加锁顺序,针对五把锁,都进行编号,约定每个线程获取锁的顺序,一定要先获取编号小的锁,后获取编号大的锁。
如果我们指定了加锁顺序,也就是指定了,哲学家拿筷子顺序,因为哲学家只能拿自己面前的两只筷子,且我们又指定了,要先获取编号小的筷子。
那么,如果从 2 号哲学家开始,当他拿筷子的时候,眼前的 1 2 两只筷子,他需要先拿 1 筷子:
2 号哲学家拿完之后,轮到 3 号哲学家,因为我们指定,需要拿编号小的筷子,所以他只能拿 2 号筷子。
4 5 号哲学家类似,他们分别只能拿 3 4 号筷子
但轮到 1 号哲学家的时候,因为我们指定了,要先获取编号小的筷子,即 1 号哲学家,要先获取面前的 1 号筷子,但此时不好意思,2 号哲学家正霸占着 1 号筷子,1 号哲学家就只能等着啦(阻塞等待)。但其实这时候 5 号筷子是空闲的,则 5 号哲学家,就可以拿 5 号筷子,和 4 号筷子组成一双筷子吃面啦,当 5 号哲学家吃完后,放下 4 5 号筷子,4 号哲学家就可以吃面了,依次 3 2 号哲学家可以吃面了,当 2 号哲学家吃完之后,放下 1 号筷子,1 号哲学家真的痛哭流涕,终于能轮上他吃面了...(虽然吃的迟,但也迟到了,这算是牺牲小自我,换取大家都能吃上面...)
对于我们的示例代码,只需要修改一下线程 2 中 锁的顺序即可打破死锁啦!
补充:那能不能我们指定,编号小的哲学家先吃面呢? ==》这是不可行的,因为大前提是“随机调度” “抢占式执行”,想办法让某个线程先加锁,未被了“随机调度”的根本原则,可行性是不高的,而约定加锁顺序,在写代码的层面上是非常容易做到的。’
解决死锁,其实是有很方案:
1. 引入额外的筷子 ==》 引入额外的锁
2. 去掉一个线程
3. 引入计数器,限制最多同时多少个线程存在
上面三种方案,其实现虽然并不复杂,但其普适性并不是很高,有时候用不了。
4. 引入加锁顺序的规则...(这种方法,普适性非常高,方案容易落地实现)
5. 学校中的操作系统课程中,会有一种“银行家算法”,这个方案,确实可以解决死锁问题,但我们在实际开发中,一般不会这么做。因为这种方法实在的太复杂了,为了解决死锁问题,实现“银行家算法”....死锁解没解决不确定,搞不好,我们在实现“银行家算法”的过程中,就出现了bug(即这种方法,理论上是可行的,实际中并不推荐。)
完!
相关文章:
多线程 - 线程安全 2 -- > 死锁问题
目录 小结复习: 线程安全: 如何解决线程安全问题? synchronized “死锁” 死锁的三种经典场景: 1. 一个线程,一把锁。 2.两个线程,两把锁。 3. N 个线程 M 把锁 完! 小结复习:…...
JavaScript函数详解
目录 一、函数的基础概念 1. 函数的定义方式 2. 函数的参数处理 3.匿名函数与立即执行函数 4.同名函数与函数提升 二、函数的作用域与闭包 1. 作用域(Scope) 2. 闭包(Closure) 三、高阶函数与函数式编程 1. 高阶函数 2…...
Python-八股总结
目录 1 python 垃圾处理机制2 yield3 python 多继承,两个父类有同名方法怎么办?4 python 多线程/多进程/协程4.1 多线程与GIL全局解释器锁4.2 多进程4.3 协程 5 乐观锁/悲观锁6 基本数据结构**1. 列表(List)****2. 元组࿰…...
整合分块请求大模型返回的测试用例及小工具显示bug修复
在之前的分块发送需求数据给大模型进行测试用例生成时,由于数据结构的改变,需要对分块的回复进行整合,正确的整合是保障系统稳定性和功能正确性的核心。随着测试需求的复杂化,这对测试工程师提出了更高的整合和管理要求。本文将为…...
记一道CTF题—PHP双MD5加密+”SALT“弱碰撞绕过
通过分析源代码并找到绕过限制的方法,从而获取到flag! 部分源码: <?php $name_POST[username]; $passencode(_POST[password]); $admin_user "admin"; $admin_pw get_hash("0e260265122865008095838959784793");…...
stm32F103RCT6 FLASH模拟EEPROM 读写32位数据
#include “stm32flash.h” #ifndef __STMFLASH_H__ #define __STMFLASH_H__ #include "main.h" #define</...
Spring Data审计利器:@LastModifiedDate详解!!!
🕒 Spring Data审计利器:LastModifiedDate详解🔥 🌟 简介 在数据驱动的应用中,记录数据的最后修改时间是常见需求。Spring Data的LastModifiedDate注解让这一过程自动化成为可能!本篇带你掌握它的核心用法…...
【SLURM】介绍
SLURM Slurm(Simple Linux Utility for Resource Management) 是一个用于管理和调度计算集群任务的开源作业调度系统。它主要用于高性能计算(HPC)环境,比如超算中心、大学的计算集群或企业的数据中心。 本文主要针对使…...
算法-贪心算法
圣诞老人的礼物-Santa Clau’s Gifts 现在有多箱不同的糖果,每箱糖果有自己的价值和重量,每箱糖果都可以拆分成任意散装组合带走。圣 诞老人的驯鹿雪橇最多只能装下重量W的糖果,请 问圣诞老人最多能带走多大价值的糖果。 输入 第一行由两个…...
Nginx — Nginx处理Web请求机制解析
一、Nginx请求默认页面资源 1、配置文件详解 修改端口号为8080并重启服务: 二、Nginx进程模型 1、nginx常用命令解析 master进程:主进程(只有一个) worker进程:工作进程(可以有多个,默认只有一…...
GAN随手笔记
文章目录 1. description2. code 1. description 后续整理 GAN是生成对抗网络,主要由G生成器,D判别器组成,具体形式如下 D 判别器: G生成器: 2. code 部分源码,暂定,后续修改 import nump…...
Java 8 时区与历法处理指南:跨越全球的时间管理
Java 8 的 java.time API 不仅修复了旧版日期时间 API 的设计缺陷,还提供了对时区和多历法的全面支持。无论是处理全球化应用的时区转换,还是适配不同文化的日历系统,Java 8 都能轻松应对。本文将深入解析其核心功能,并提供实用代…...
【STM32】对stm32F103VET6指南者原理图详解(超详细)
目录 一、原理图基本概念二、STM32F103VET6 的主要特性二、MCU模块三、电源模块四、时钟模块五、复位模块NRST 六、GPIO模块LED 七、调试模块JTAG 八、外设模块UARTSPII2CADC 九、其它模块BOOT 一、原理图基本概念 原理图/电路图通常由硬件工程师使用Altium Designer/ KiCad / …...
瑞芯微RKRGA(librga)Buffer API 分析
一、Buffer API 简介 在瑞芯微官方的 librga 库的手册中,有两组配置 buffer 的API: importbuffer 方式: importbuffer_virtualaddr importbuffer_physicaladdr importbuffer_fd wrapbuffer 方式: wrapbuffer_virtualaddr wrapb…...
移动端六大语言速记:第1部分 - 基础语法与控制结构
移动端六大语言速记:第1部分 - 基础语法与控制结构 本文将对比Java、Kotlin、Flutter(Dart)、Python、ArkTS和Swift这六种移动端开发语言的基础语法与控制结构,帮助开发者快速理解各语言间的差异与共性。 1. 基础语法 1.1 数据类型 各语言的基本数据…...
Java 大视界 -- Java 大数据在智能金融区块链跨境支付与结算中的应用(154)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
Python Playwright库全面详解
Playwright 是 Microsoft 开发的一个现代化的端到端测试和浏览器自动化库,支持 Chromium、WebKit 和 Firefox 浏览器。它提供了跨浏览器、跨平台的自动化能力,且具有高性能和可靠性。 一、核心特性 多浏览器支持: Chromium (Chrome, Edge)We…...
脑疾病分类的疑惑【6】:脑疾病分类比较适合使用具有哪些特点的模型?
脑疾病分类是一个复杂的任务,涉及医学影像、神经电生理信号、基因数据等多种信息类型。为了有效地进行脑疾病分类,选择合适的模型是至关重要的。以下是一些适合脑疾病分类的模型特点,您可以参考这些特点来选择合适的模型: 1. 深度…...
24_原型和原型链_this
目录 一、this关键字 修改this的指向 二、原型和原型链 三、创建对象 通过构造函数创建 (es5) 通过类创建 (es6) 四、浅拷贝和深拷贝 ctrlc 浅拷贝: 只拷贝一层 深拷贝: 可以拷贝多层 一、this关键字 每个函…...
自定义类型:结构体(1)
1.结构体回顾 结构是一些值的集合,这些值被称为成员变量。结构的每个成员可以是不同类型的变量。 1.1结构的声明 struct tag {member-list; }variable-list;例如描述一个学生: struct Stu {char name[20];int age;char sex[5]; }; 1.2结构体变量的创…...
Java进阶——Lombok的使用
Lombok可以通过注解的方式,在编译时自动生成 getter、setter、构造函数、toString 等样板代码,从而减少代码的冗余,提高开发效率。本文深入讲解Lombok在实际开发中的使用。 本文目录 1. Lombok 依赖添加2. 常用Lombok注解及使用场景2.1 Gette…...
饿了么 bx-et 分析
声明: 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向分析 import requests bx_et re…...
python黑科技:无痛修改第三方库源码
需求不符合 很多时候,我们下载的 第三方库 是不会有需求不满足的情况,但也有极少的情况,第三方库 没有兼顾到需求,导致开发者无法实现相关功能。 如何通过一些操作将 第三方库 源码进行修改,是我们将要遇到的一个难点…...
PGD对抗样本生成算法实现(pytorch版)
PGD对抗样本生成算法 一、理论部分1.1 PGD 原理(1) 数学形式(2) 核心改进1.2 PGD 与其他攻击对比1.3 注意事项二、代码实现2.1 导包2.2 数据加载和处理2.3 网络构建2.4 模型加载2.5 生成对抗样本2.6 对抗测试2.7 启动攻击2.8 效果展示一、理论部分 1.1 PGD 原理 PGD 是 BIM/I-…...
小智机器人相关函数解析,BackgroundTask::Schedule (***)将一个回调函数添加到后台任务队列中等待执行
以下是对 BackgroundTask::Schedule 函数代码的详细解释: void BackgroundTask::Schedule(std::function<void()> callback) {std::lock_guard<std::mutex> lock(mutex_);if (active_tasks_ > 30) {int free_sram heap_caps_get_free_size(MALLOC_…...
C++学习之路:深入理解变量
目录 编程的本质变量的本质内存模型、变量名与值以及地址的关系数据类型C数据类型数据类型别名数据类型转换 变量作用域总结 编程的本质 编程的本质是什么?虽然程序里能实现很多复杂的逻辑,但是从底层的硬件上来看,编程的本质就是数据的搬移。…...
前端基础知识汇总
目录 HTML5详解(结构层) 什么是HTML HTML基本结构 网页基本信息 图像标签 链接标签 超链接 行内元素与块元素 列表标签 表格标签 页面结构分析 iframe内联框架 表单语法 表单元素格式 表单的简单应用 表单初级验证 CSS详解(…...
2024蓝桥杯省赛C/C++大学B组 题解
文章目录 2024蓝桥杯省赛C/C大学B组A 握手问题(5分)B 小球反弹(5分)C 好数(10分)D R 格式(10分)E 宝石组合(15分)F 数字接龙(15分)G 爬…...
BIM/I-FGSM对抗样本生成算法实现(pytorch版)
BIM/I-FGSM对抗样本生成算法 一、理论部分1.1 核心思想1.2 数学形式1.3 BIM 的优缺点1.4 BIM 与 FGSM、PGD 的关系1.5 实际应用建议二、代码实现2.1 导包2.2 数据加载和处理2.3 网络构建2.4 模型加载2.5 生成对抗样本2.6 攻击测试2.7 启动攻击2.8 效果展示一、理论部分 1.1 核心…...
前沿科技:从Gen2到Gen3—Kinova轻型机械臂的技术升级路径
Kinova品牌在轻型机械臂行业中以其轻量化、灵活性和高精度的技术特点而知名。其产品线广泛适用于医疗、科研和工业等多个领域,对机器人技术的进步起到了积极的推动作用。Kinova轻型机械臂凭借其精良的设计和稳定的性能,为用户提供了高效且可靠的解决方案…...
智研咨询:2025DeepSeek技术全景解析重塑全球AI生态的中国力量|附下载方法
导 读INTRODUCTION 随着人工智能技术的飞速发展,AI大模型已成为推动行业进步的重要力量。智研咨询最新发布的《DeepSeek技术全景解析重塑全球AI生态的中国力量》报告,深入探讨了DeepSeek公司在AI领域的突破性成就及其对全球AI生态的深远影响。 如果感兴…...
超导量子计算机编程实战:IBM Qiskit 2025新API详解
一、量子计算平台演进与Qiskit 2025定位 1.1 IBM量子硬件发展路线 2025年IBM将实现三大技术突破: 量子体积:新一代"Goldeneye"处理器达到QV 8192相干时间:超导量子比特寿命突破500μs互联规模:模块化架构支持万级量子…...
斐波那契数列----C语言
关于斐波那契 已知: 问题背景:一对兔子从第3个月开始每月生一对新兔子,新兔子同样在第3个月开始繁殖。 关键观察: 第1个月:1对(初始兔子)。 第2个月:1对(未成熟&#…...
打开pycharm显示编制索引后卡死
若项目中包含过多文件,PyCharm 启动后会进行自动索引,电脑性能不高时往往会导致崩溃(主要是内存问题)。以下为解决措施。 ✅ 1. 仅索引代码,排除文件 设置PyCharm 主要索引代码文件(.py、.ipynbÿ…...
AWS云安全全面详解:从基础防护到高级威胁应对
随着企业加速向云端迁移,AWS作为全球最大的云服务提供商之一,其安全性成为用户首要关注的问题。本文将深入剖析AWS云安全架构,从基础防护到高级威胁应对,帮助您构建全方位的云安全防线。 一、AWS安全责任共担模型 在深入探讨AWS具体安全措施前,首先需要理解AWS的安全责任…...
【C++重点】虚函数与多态
在 C 中,虚函数是实现多态的基础。多态是面向对象编程的重要特性之一,允许程序在运行时决定调用哪一个函数版本。通过虚函数,我们能够实现动态绑定,使得不同类型的对象可以通过相同的接口进行操作。 1 静态绑定与动态绑定 静态绑…...
算法学习之BFS
关于BFS我的理解是根据离我们当前这个点的权重来移动,这里权重也可以理解为离这个点的距离, 从起点开始,往前走一步,记录下所有第一步能走到的点开始,然后从所有第一部能走到的点开始向前走第二步,重复下去…...
每日小积累day1
网络: g是用来检测网络联通性的的诊断工具,使用的协议是ICMP 显示数据包括 ICMP数据:序列号,存活时间(TTL) 目标主机域名IP 往返时间(RTT) 统计数据(平均RTT等等&a…...
【NLP】13. NLP推理方法详解 --- 穷举和贪心搜索
NLP推理方法详解 — 穷举和贪心搜索 在自然语言处理(NLP)任务中,推理(Inference)是指在给定模型的情况下,找到最可能的输出序列。由于模型通常是神经网络,它会为每个可能的输出分配一个概率&am…...
基于 Python 深度学习 lstm 算法的电影评论情感分析可视化系统(2.0 系统全新升级,已获高分通过)
大家好,欢迎来到我的技术专栏!今天我将和大家聊聊如何利用 Python 的深度学习技术,打造一个集电影评论情感分析与可视化展示于一体的系统。这个系统不仅能自动采集和解析海量影评,还能实时生成直观的情感趋势图表,对于…...
妙用《甄嬛传》中的选妃来记忆概率论中的乘法公式
强烈推荐最近在看的不错的B站概率论课程 《概率统计》正课,零废话,超精讲!【孔祥仁】 《概率统计》正课,零废话,超精讲!【孔祥仁】_哔哩哔哩_bilibili 其中概率论中的乘法公式,老师用了《甄嬛传…...
linux--------------进程控制
1.进程创建 1.1fork函数初识 在linux中fork函数是⾮常重要的函数,它从已存在进程中创建⼀个新进程。新进程为⼦进程,⽽原进 程为⽗进程。 #include <unistd.h> pid_t fork(void); 返回值:⾃进程中返回0,⽗进程返回⼦进程id…...
Video Transformer Network
目录 摘要 Abstract VTN 背景 模型框架 视频特征提取 时空位置编码 Transformer编码器 任务特定头 关键创新 实验 代码 总结 摘要 Video Transformer Network 是基于Transformer架构改进的视频理解模型,旨在解决传统3D卷积神经网络在长距离依赖建模和…...
Java网络编程演进:从NIO到Netty的UDP实践全解析
前言 在当前高并发、大数据量的互联网环境下,高性能的网络通信框架变得越来越重要。本文将深入探讨Java网络编程的演进,从NIO到Netty,并通过实际案例分析Netty的优势和应用。(本次主要以UDP请求为例) Java网络编程演…...
Linux系统中快速安装docker
1 查看是否安装docker 要检查Ubuntu是否安装了Docker,可以使用以下几种方法: 方法1:使用 docker --version 命令 docker --version如果Docker已安装,输出会显示Docker的版本信息,例如: Docker version …...
人工智能之数学基础:幂法和反幂法求特征值和特征向量
本文重点 特征值和特征向量是矩阵的重要性质,我们前面学习了矩阵的正交分解,要想完成正交分解需要求出一个矩阵的特征值和特征向量。有的时候,我们只需要求出一个矩阵的最大的特征值以及矩阵的最小特征值,它们以及它们对应的特征向量具有特殊的含义,下面我们介绍两种方法…...
数据结构 -- 树的应用(哈夫曼树和并查集)
树的应用 哈夫曼树 带权路径长度 结点的权:有某种现实含义的数值(如:表示结点的重要性等) 结点的带权路径长度:从树的根到该结点的路径长度(经过的边数)与该结点上权值的乘积 树的带权路径…...
游戏引擎学习第193天
仓库:https://gitee.com/mrxiao_com/2d_game_4 回顾 我们昨天做了一些非常有趣的实验。在实验中,我们的目标是实现一个能够在运行时改变的编译时常量的概念。最开始,这个想法纯粹是出于一时的兴趣,觉得这应该是个很有意思的尝试。于是我们进…...
数据结构每日一题day7(顺序表)★★★★★
题目描述:从顺序表中删除其值在给定值s与t之间(包含s和 t,要求 s<t)的所有元素,若s或t不合理或顺序表为空,则返回 false,若执行成功则返回 true。 算法思想: 输入检查:若顺序表为空、指针为…...
ACM模式常用方法总结(Java篇)
文章目录 一、ACM输入输出模式二、重要语法2.1、导包2.2、读取数据2.3、判断是否有下一个数据2.4、输出2.5、关闭scanner2.6、易踩坑点 一、ACM输入输出模式 在力扣上编写代码时使用的是核心代码模式,如果在面试中遇到ACM模式就会比较迷茫?ACM模式要求你…...