当前位置: 首页 > news >正文

【Java ee初阶】多线程(4)

一、java是怎么做到可重入的

java中,通过synchronized进行加锁,指定一个()包含了一个锁对象。(锁对象本身是一个啥样的对象,这并不重要,重点关注锁对象是不是同一个对象)

后面搭配{}.进入遇到{就触发加锁操作 遇到 } 就触发解锁操作 防止解锁操作被遗忘

如果一个线程加锁,一个线程不加锁;一个线程针对locker1加锁,一个线程针对locker2加锁......

锁相当于都不会产生冲突,不会产生阻塞。

二、synchronized的特性

1.互斥

2.可重入 一个线程,一把锁,这个线程针对这个锁,连续加锁两次

synchronized(locker){

synchronized(locker)

}

locker已经是被加锁的状态了.尝试对一个已经上了锁进行加锁,就会产生阻塞

此处阻塞的接触,需要先释放第一次锁

要想释放第一次加锁,需要先加上第二次的锁

一个线程针对一把锁,连续加锁多次,不会触发死锁——>可重入

可重入这个现象是如何做到的呢?

让锁对象本身,记录下来拥有者是哪个线程(把线程id给保存下来了)

Object...Java的对象,除了又一个内存区域,保存程序员自定义的成员之外,还有一个隐藏区域,用来保存“对象头”。

对象头是JVM去维护的,保存了这个对象的一些其他运行信息,例如,加锁状态,哪个线程加了锁等等。

当我们已经给一个对象加锁了,后序再去针对这个对象加锁,那么就会先判定,当前尝试加锁的线程,是不是已经持有这个锁的线程。如果没有,才触发阻塞,如果有,不触发阻塞,直接放行。

二、死锁的情况

可重入锁,只能处理死锁的其中一种情况,没办法处理其他情况

1.一个线程一把锁,连续加锁两次

2.两个线程两把锁,每个线程先获得一把锁,再尝试获取对方的锁

package Thread;public class demo24 {private static Object locker1 = new Object(); private static Object locker2 = new Object(); public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> { synchronized (locker1) { System.out.println("t1拿到了locker1");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized (locker2) { System.out.println("t1拿到了locker2");  }}
});Thread t2 = new Thread(() -> {synchronized (locker2) { System.out.println("t2拿到了locker2");try {Thread.sleep(1000);}   catch (InterruptedException e) {}synchronized (locker1) { System.out.println("t2拿到了locker1");}  }   });t1.start();t2.start();t1.join(); // 等待t1线程执行完毕,才能继续执行后面的代码t2.join(); // 等待t2线程执行完毕,才能继续执行后面的代码}}

输出:

3.N个线程M把锁,也会构成死锁

“哲学家就餐问题”

三、如何避免死锁的出现

死锁这样的情况就是会客观发生的,线程一旦出现死锁,线程就卡死了,不动了,后序的逻辑就无法正常执行了,这是bug

如何避免代码中出现死锁呢?

关键在于理解死锁的“四个必要条件”

1.锁是互斥的——我们现在正在学习的synchronized是互斥的

2.锁不可被抢占——线程1拿到锁之后,线程2也想要这个锁,线程2会阻塞等待,而不是直接把锁抢过来

(对于synchronized来说,条件1和条件2 都是synchronized的基本特点)

3.请求和保持——拿到第一把锁的情况下,不去释放第一把锁,再尝试请求第二把锁(*确实有一定的场景是需要拿到锁1 的前提下再尝试去拿锁2)

4.循环等待——等待锁释放,等待的关系(顺序)构成了循环

(*也就是不要让等待关系构成循环 针对锁进行编号

;约定,加多个锁的时候,必须按照一定的顺序来加锁,比如按照编号从小到大的顺序)

上述两种是开发中比较实用的方法,还有一些其他的方案,也能解决死锁问题。

package Thread;public class demo24 {private static Object locker1 = new Object(); private static Object locker2 = new Object(); public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> { synchronized (locker1) { System.out.println("t1拿到了locker1");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}synchronized (locker2) { System.out.println("t1拿到了locker2");  }
});Thread t2 = new Thread(() -> {synchronized (locker2) { System.out.println("t2拿到了locker2");try {Thread.sleep(1000);}   catch (InterruptedException e) {}}   //把第二把锁的加锁操作放到第一把锁的外面,先释放第一把锁,再获取第二把锁,这样就不会出现死锁的情况了。synchronized (locker1) { System.out.println("t2拿到了locker1");}  });t1.start();t2.start();t1.join(); // 等待t1线程执行完毕,才能继续执行后面的代码t2.join(); // 等待t2线程执行完毕,才能继续执行后面的代码}}

四、Java 标准库中的线程安全类

Java 标准库中很多都是线程不安全的. 这些类可能会涉及到多线程修改共享数据, 也没有任何加锁措施

这些常用的集合类,大多是线程不安全的,把加锁策略交给程序员

但是还有⼀些是线程安全的. 使用了一些锁机制来进行控制

其中 Vector 和 HashTable 是Java早年间起,各位java大佬还不够成熟的时候引入的设定

现在的话这些设定已经被推翻,不建议再使用

有的虽然没有加锁, 但是不涉及 "修改", 仍然是线程安全的

*解决线程安全问题,我们使用加锁的方式。但是加锁是有代价的,加锁会非常明显地影响到程序的执行效率。加锁意味着可能触发锁竞争,一旦触发竞争就会产生阻塞。某个线程一旦因为加锁阻塞,能回来继续执行任务的时间就不确定了。写代码的时候需要考虑清楚某个地方是否要加锁。

五、内存可见性引起的线程安全问题

package Thread;public class Demo15 {public static int count = 0; // 共享变量,多个线程共同修改的变量,称为共享变量public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> { // 线程t1for (int i = 0; i < 5000; i++) { // 循环5000次count++; // 自增操作,相当于count = count + 1}});Thread t2 = new Thread(() -> { // 线程t2for (int i = 0; i < 5000; i++) { // 循环5000次count++; // 自增操作,相当于count = count + 1}});t1.start(); // 启动线程t1t2.start(); // 启动线程t2// 等待线程t1和线程t2执行完毕t1.join(); // 等待线程t1执行完毕t2.join(); // 等待线程t2执行完毕System.out.println(count); // 打印count的值,应该是10000,因为每个线程都自增了5000次}}

这个问题产生的原因,就是“内存可见性”

flag变量的修改,对于t1线程“不可见了”,t2修改了flag,但是t1看不见

编译器优化

主流编程语言,编译器的设计者(对于Java来说,谈到的编译器包括javac和jvm)考虑到一个问题:实际上写代码的程序员,水平是参差不齐的(具有一定的差距)

虽然有的程序员水平不高,写的代码效率比较低,编译器在编译执行的时候,分析理解现有代码的意图和效果,然后自动对这个代码进行调整和优化,在确保程序执行逻辑不变的前提下,提高程序的效率。

编译器优化的效果是很明显,但是大前提是“程序的逻辑不变”

大多数情况下,编译器优化,都可以做到“逻辑不变的前提”

但是在有些特定场景下,编译器优化可能出现“误判”,导致逻辑发生改变。

“多线程代码”

对于这个程序来说,编译器看到的效果是:有一个变量flag,会快速地,反复地读取整个内存的值(反复执行load\cmp\load\cmp);同时,反复执行的过程中,每次拿到的flag的值还都是一样的,上述的load操作相比cmp,耗时会多很多,读取内存,比读取寄存器,效率会慢很多(几百倍,几千倍)

既然load读取的值都是一样的,而且load开销这么多,于是编译器直接把从内存读取flag这个操作给优化掉了。上述操作只是前几次读内存,后面发现一样,就干脆从读好的寄存器中直接获取这个flag的值,此时,循环的侠侣就大幅度地提升了。

编译器不确定这里的flag修改代码到底能不能执行,以及啥时候执行。

上述内存可见性问题,是编译器优化机制,自身出现的bug。

六、volatile关键字

通过这个关键字,提醒编译器,某个变量是“易变”的,此时就不要针对这个易变的变量进行上述优化。

给变量添加了volatile关键字,编译器在看到volatile的时候,就会提醒JVM运行的时候不进行上述的优化。

在读写volatile变量的指令前后添加“内存屏障相关的指令”

JMM Java Memory Model

Java的内存模型

首先一个Java进程,会有一个“主内存”存储空间,每个Java线程又会有自己的“工作内存”存储空间

形如上述的代码,t1进行flag变量的判定时,就会把flag的值从主内存,先读取到工作内存,再用工作内存中的值进行判定。同时,t2对flag进行修改,修改的则是主内存的值,主内存的值的修改不会影响到t1的工作内存。

上述解释,出自于Java的官方文档

main memory(主内存)就是内存 

work memory (工作内存)相当于是打了个比方,本质上这一块区域并不是内存,而是CPU的寄存器和CPU的缓存构成的统称

Java自身是希望做成“跨平台”,Java用户不需要了解系统底层和硬件差异。Java的设计者是不希望用户了解这些底层细节的。另一方面,不同的CPU底层结构也不一定相同。

抛开Java上下文不谈,只关注操作系统和硬件,没有上面“主内存”“工作内存”的说法的。

存储数据,不只是有内存,还有外存(硬盘),还有cpu寄存器,cpu上还有缓存。

现代CPU都引入了缓存,CPU的缓存空间比寄存器要大,速度要比寄存器要慢,但是比起内存还是要快。

CPU的寄存器和缓存,就统称为work memory 

越往上,速度就越快,空间就越小,成本就越高。

编译器优化,就是把本来要从内存中读取的值,优化成从寄存器中读取。

可能是优化成从寄存器上读取,也可能是优化成从L1缓存上读取,也可能是优化成从L2缓存上读取,也可能是优化成从L3缓存上读取……(都没有从内存上重新读取,因此读不到最新的修改之后的数值)

编译器优化,并非是100%触发,根据不同的代码结构,可能产生出不同的优化效果(有优化/无优化/优化方式)

此处虽然没有写volatile,但是加了sleep也会使得上述程序不在优化。

因为:

1.循环速度大幅度降低了

2.有了sleep一次循环的瓶颈,就不是load,此时再优化load,就没有什么用了。

3.sleep本身会触发线程调度,调度过程触发上下文切换。

volatile这个关键字,能够解决内存可见性引起的线程安全问题,但是不具备原子性这样的特点。

synchronized和volatile是两个不同的维度,前者是两个线程都修改,volatile是一个线程读,另一个线程修改。

六、wait/notify

这两个关键字是用来协调线程之间的执行顺序的

两个线程在运行的时候,都是希望持续运行下去的(不涉及结束)。但是两个线程中的某些环节,我们希望能够有一定的先后顺序。

*线程执行本身是随即调度的(顺序不确定),join控制线程的结束顺序

例如线程1 ,线程2

希望线程1 先执行完某个逻辑之后,再让线程2去执行。

此时就可以让线程2通过wait主动进行阻塞,让线程1先参与调度,等线程1把对应的逻辑执行完了,就可以通过notify唤醒线程2.

另外,wait / notify 也能解决“线程饿死”的问题。

当线程1释放锁之后,其他线程就要竞争这个锁(线程1 自身也可以重复参与到竞争中)

由于其他线程还要等待操作系统唤醒,此时线程1就是在cpu上执行,就有很大的可能性,“捷足先登”

不像死锁,死锁发生,就僵硬住,除非程序启动,否则就会一直僵持。

线程饿死,没那么严重,在线程1反复获取几次锁之后,其他线程也是有机会拿到锁的,但是其他线程拿到锁的时间会延长,降低了程序的效率。

相关文章:

【Java ee初阶】多线程(4)

一、java是怎么做到可重入的 java中&#xff0c;通过synchronized进行加锁&#xff0c;指定一个&#xff08;&#xff09;包含了一个锁对象。&#xff08;锁对象本身是一个啥样的对象&#xff0c;这并不重要&#xff0c;重点关注锁对象是不是同一个对象&#xff09; 后面搭配…...

Day15(贪心算法)——LeetCode121.买卖股票的最佳时机55.跳跃游戏

1 LeetCode121.买卖股票的最佳时机(LeetCode121) 1.1 题目描述 题目描述如下:   示例如下&#xff1a; 1.2 问题分析及解决 要求最大利润&#xff0c;即当天与之前天的价格之差最大值。因此我们可以遍历数组&#xff0c;记录下当前遇到的最小值&#xff0c;然后用当天的价…...

2025汽车制造企业数字化转型路径参考

以应用场景作为切入点&#xff0c;引导相关企业推进数字化深度转型和规模化改造&#xff0c;是目前实践探索出来的一条可行路径。 汽车制造行业是相对集聚的制造业领域&#xff0c;通过搭建“转型场景图谱——转型通用工具——转型路径指引”分析框架&#xff0c;聚焦需求侧共…...

雷池WAF的身份认证 - GitHub

雷池支持通过 GitHub 认证的方式&#xff0c;让用户使用 GitHub 身份安全登录应用或网站。使用此功能需要 GitHub 账号 。 第一步&#xff1a;在 GitHub 创建一个 OAuth 应用 可参阅 GitHub 官方文档&#xff0c;创建一个 GitHub OAuth 应用&#xff0c;并获取应用的 ClientI…...

【Linux】第十二章 安装和更新软件包

目录 1. 什么是RPM&#xff1f; 2. dnf是什么&#xff0c;它和rpm有什么联系和区别&#xff1f; 3. RHEL 中如何做才能启用对第三方存储库的支持&#xff1f; 4. 怎么理解RHEL9中的应用流(Application Streams)和模块(Modules)&#xff1f; 5. RHEL9 有两个必要的软件存储…...

【权限模型】RBAC模型详解

大家好&#xff0c;我是jstart千语。今天给大家介绍一下鉴权模型RBAC&#xff0c;传统的鉴权模式就是基于用户和权限之间的多对多关系。而RBAC就更加的精准&#xff0c;更好管理。 RBAC介绍 RBAC&#xff08;Role-Based Access Control&#xff09;是一种通过角色&#xff08;…...

tree命令

tree [选项] [目录...] 指定要显示的目录。如果没有指定目录&#xff0c;tree 会显示当前目录及其子目录结构。 常用选项 -a 显示所有文件和目录&#xff0c;包括隐藏文件&#xff08;以 . 开头的文件&#xff09;。 -d 只显示目录&#xff0c;不显示文件。 -L LEVEL …...

【Vue.js】组件数据通信:基于Props 实现父组件→子组件传递数据(最基础案例)

概览 前言父子通信流程关键技术点关键规则 实战1. 在父组件中注册子组件2. 子组件接收父组件传入的数据补充与总结 前言 在 Vue 3 中&#xff0c;父组件向子组件传递数据是通过props实现的。父组件在子组件的标签上绑定数据&#xff0c;子组件通过定义props接收这些数据。这种…...

信创时代技术栈选择与前景分析:国产替代背景下的战略路径与实践指南

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…...

Python内置方法干货总结

如果你还在为提升Python代码能力发愁&#xff0c;那么掌握内置方法就是你的捷径&#xff01;很多初学者和进阶者忽略了这一“宝藏”&#xff0c;其实&#xff0c;Python的内置方法不仅能让你代码更简洁&#xff0c;还能大幅提升开发效率。今天&#xff0c;咱们就来一次系统梳理…...

小草GrassRouter多卡聚合路由器聚合卫星、MESH网络应用解决方案

一、多网融合解决方案 卫星网络融合‌ 支持接入卫星通信模块&#xff0c;在无地面网络覆盖的极端场景&#xff08;如偏远山区、海洋救援&#xff09;下&#xff0c;形成“5G卫星”双链路冗余传输&#xff0c;卫星链路可作为核心通信备份&#xff0c;确保关键指令和视频数据实…...

Spring反射机制

Spring反射机制 反射机制是加载类时&#xff0c;在运行时动态地获取类的信息&#xff0c;并且可以操作类或对象的属性、方法、构造函数等成员的能力。在 Java 里&#xff0c;反射机制的实现主要依赖于 java.lang.reflect 包下的多个类&#xff0c;以及 java.lang 包中的 Class…...

PCB硬件电路设计_pcb布线设计

1.MCU最小系统电路 这些电路都会非常接近MCU&#xff0c;他们的可靠性决定了MCU能否正常工作。 外围电路&#xff0c;为了布线整齐美观&#xff0c;尽量避免打过多的通孔。在布局的时候走线的顺序和元器件顺序尽可能的保持一直避免走线交叉。 2.晶振电路布线 一般情况下我们…...

Qt开发:XML文件的写入与读取

文章目录 一、使用 QDomDocument操作节点1.1 将信息写入XML文件中1.2.从XML文件中读取信息 二、使用 QXmlStreamWriter操作节点2.1 将信息写入XML文件中2.2 从XML文件中读取信息 三、总结 一、使用 QDomDocument操作节点 1.1 将信息写入XML文件中 #include <QDomDocument&…...

PCI/PXI 总线的可编程电阻卡

701X 系列是阿尔泰科技基于 PCI/PXI 总线的可编程电阻卡&#xff0c;多种电阻范围可选&#xff0c;稳定性好&#xff1b;准确 度低至 0.2%&#xff1b;分辨率设置精细&#xff0c;可低至 0.125Ω&#xff0c;适用于传感器仿真应用。 701X 系列高精度程控电阻模块具有高设置分辨…...

火语言RPA--腾讯云存储

【组件功能】&#xff1a;存储本地文件至腾讯云 选择本地文件&#xff0c;通过腾讯云存储配置上传至腾讯云对象存储的指定地域指定存储桶指定路径。 配置预览 配置说明 SecretId 支持T或# 前往官网获取或创建。参考链接&#xff1a;https://console.cloud.tencent.com/cam/…...

使用POI和EasyExcel使用导入

1.使用POI导入 1.1导入依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency> 1.2创建工具类 package com.ruoyi.common.utils.poi;import org.ap…...

AWS PrivateLink vs Lattice:深度解析两大网络服务的异同

导语: 在AWS的网络服务生态中,PrivateLink和Lattice都是备受关注的解决方案。本文将深入探讨这两项服务的核心特性、应用场景以及它们之间的关键区别,帮助您在复杂的网络架构设计中做出明智的选择。 一、AWS PrivateLink 概述 定义 AWS PrivateLink 是一种网络服务,允许您…...

Linux系统编程---exec簇:进程的加载与替换

1、exec簇基础 在Linux中&#xff0c;用于加载并执行指定程序的API有exec簇和system函数。 exec簇的进程替换不会创建一个新的进程&#xff0c;只是加载新的程序代码和数据&#xff0c;替换当前进程执行的程序代码。 system函数的进程替换是创建一个新的子进程&#xff0c;然后…...

C++ 之 【模拟实现 list(节点、迭代器、常见接口)】(将三个模板放在同一个命名空间就实现 list 啦)

1.前提准备 (1) list 的底层结构一般是带头双向循环链表 (1)为避免命名冲突&#xff0c;需要创建一个命名空间来存放模拟实现的 list (2)下面模拟实现list时&#xff0c;声明和定义不分离(具体原因后续讲解) 2.完整实现 2.1 链表节点 template<class T>//节点写成类模板…...

数字图像处理 -- 眼底图像血管分割方法

算法框架 基于深度学习的 U-Net 架构&#xff0c;结合注意力机制&#xff08;Attention Gate&#xff09;与多尺度特征提取&#xff0c;以提高细小血管的检测能力。整体流程如下&#xff1a; 输入图像预处理&#xff1a;提取绿色通道 & CLAHE 增强数据增强&#xff1a;旋…...

基于ffmpeg的音视频编码

1 音频编码 本质上是由pcm文件转到一个协议文件 比如说aac协议 1.1 音频基本知识回归 比特率 比特率是指单位时间内传输或处理的比特&#xff08;bit&#xff09;数量&#xff0c;通常用 bps&#xff08;bits per second&#xff0c;比特每秒&#xff09;来表示。它是衡量数…...

Android wifi开发调试总结

Android wifi开发调试简单总结 文章目录 Android wifi开发调试简单总结一、前言二、wifi demo开发1、开关和连接2、wifi开启主要流程3 、wifi主要广播4、相关日志5、demo示例 三、其他1、Wifi开发小结2、其他wifi知识小结&#xff08;1&#xff09;Android无线Wifi开发&#xf…...

LLVIP、KAIST、M3FD数据集

LLVIP、KAIST、M3FD数据集 &#xff08;可见光红外&#xff0c;双模态数据集&#xff0c;已配准已对齐已清洗&#xff0c;已处理为txt格式&#xff0c;YOLO可直接训练&#xff09; 电子产品&#xff0c;一经出售&#xff0c;概不退换 算法设计、毕业设计、期刊专利&#xff01;…...

datasets 数据处理封装后,统一处理流程以避免Dataset Map顺序依赖问题

文章目录 处理流程说明小结 在实际项目中&#xff0c;我们常常需要对数据集进行预处理。为了规范操作&#xff0c;我封装了一个基础数据集处理类&#xff1a; class DatasetAbstract:"""所有数据集都应包含以下几个字段&#xff1a;* question&#xff1a;用户…...

【学习笔记】机器学习(Machine Learning) | 第四章(3)| 多变量线性回归

机器学习&#xff08;Machine Learning&#xff09; 简要声明 基于吴恩达教授(Andrew Ng)课程视频 BiliBili课程资源 文章目录 机器学习&#xff08;Machine Learning&#xff09;简要声明 三、特征工程与多项式回归&#xff08;一&#xff09;特征工程&#xff1a;从数据中发…...

将本地Springboot项目部署到Linux服务器

1、打包后端项目 在IDEA的终端上执行命令 mvn clean package "-Dmaven.test.skiptrue" 在target目录下查看jar包是否存在 2、idea运行jar包&#xff08;可选&#xff09; 在IDEA的终端上执行命令 # 进入jar包所在目录 E:\LzpWorkspaces\lzp-records> cd .\tar…...

无人设备遥控器之实时数据保护技术篇

无人设备遥控器的实时数据保护技术是保障设备安全运行、避免信息泄露或恶意干扰的核心手段&#xff0c;其核心目标是在复杂电磁环境和网络攻击威胁下&#xff0c;确保指令传输的完整性、保密性和抗干扰性。 一、技术实现路径 链路层加密与认证 动态密钥协商&#xff1a;采用…...

【优秀三方库研读】【性能优化点滴】odygrd/quill 解决伪共享

一、伪共享&#xff08;False Sharing&#xff09;问题本质 当不同CPU核心频繁修改**同一缓存行&#xff08;Cache Line&#xff09;**中的不同变量时&#xff0c;会导致严重的性能下降。现代CPU的缓存系统以缓存行&#xff08;通常64字节&#xff09;为单位操作内存&#xff…...

JavaScript性能优化实战(6):网络请求与资源加载优化

引言 在现代Web应用开发中,网络性能已成为影响用户体验的关键因素。据统计,用户等待页面加载的耐心通常不超过3秒,超过这个时间,约40%的用户会选择离开。此外,Google的研究表明,页面加载时间每增加0.5秒,流量就会下降约20%。因此,优化网络请求和资源加载不仅关乎用户体…...

re题(49)BUUCTF-crackMe

BUUCTF在线评测 int wmain() {FILE *v0; // eaxFILE *v1; // eaxchar v3; // [esp3h] [ebp-405h]char v4[256]; // [esp4h] [ebp-404h] BYREFchar Format[256]; // [esp104h] [ebp-304h] BYREFchar v6[256]; // [esp204h] [ebp-204h] BYREFchar v7[256]; // [esp304h] [ebp-10…...

Python中的单例模式:深入探索元类与装饰器实现

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 单例模式(Singleton Pattern)是设计模式中的一种重要模式,确保一个类在整个应用中只有一个实例,并且提供全局访问点。Python语言作为一…...

深入解析 Babylon.js 中的 TransformNode.lookAt 方法

在 3D 开发中&#xff0c;控制对象朝向是一个基础但关键的需求。Babylon.js 作为一款强大的 Web3D 引擎&#xff0c;提供了 TransformNode.lookAt 方法来实现这一功能。本文将全面解析这个方法的使用技巧、参数含义以及常见应用场景。 方法基础 TransformNode.lookAt 的基本签…...

SpringCloud组件——Gateway

一.网关 1.问题提出 我们通过Eureka&#xff0c;Nacos解决了服务注册&#xff0c;服务发现的问题&#xff0c;使用SpringCloud LoadBalance解决了负载均衡的问题&#xff0c;使用OpenFeign解决了远程调用的问题。 但是当前所有微服务的接口都是直接对外暴露的&#xff0c;可…...

Boost 库安装 (windows 11)

Boost 库安装 (windows 11 1 下载2 生成3 使用 1 下载 下载地址&#xff1a;https://www.boost.org/ 有的时候会需要历史版本下载&#xff1a; https://www.boost.org/users/history/ 2 生成 1、解压后点击 bootstrap.bat&#xff0c;会生成可执行程序b2.exe 2、双击运行b2.…...

lmms-eval--微调实战笔记

lmms-eval--大模型调用平台&#xff0c;方便新手上手大模型微调 lmms-eval的更多用法,没有mathversehttps://github.com/EleutherAI/lm-evaluation-harness.git 单卡运行&#xff0c;模型gpt-j-6B&#xff0c;数据集hellaswag git clone --depth 1 https://github.com/Eleuthe…...

序列密码算法ShanLooog512设计原理详解

序列密码算法ShanLooog512设计原理详解 ShanLooog512(闪龙512)为序列密码算法&#xff0c;内部状态为512比特&#xff0c;密钥长度为128或256比特&#xff0c;轮函数为FFFFFFFF&#xff0c;循环轮数为24轮&#xff0c;输出密钥流为512比特的状态。与Salsa20类似&#xff0c;内…...

Matplotlib可视化基础

1. 折线图 matplotlib.pyplot.plot() # 主要参数&#xff1a; x,y -- 接收array&#xff0c;表示X轴和Y轴对应的数据&#xff0c;无默认 color -- 接收特定string&#xff0c;指定线条的颜色&#xff0c;默认为None linestyle -- 接收特定string&#xff0c;指定线条的类型…...

Linux 内核网络协议栈中的关键数据结构:inet_skb_parm 与 ip_options

在 Linux 内核的网络协议栈中,数据包的高效处理依赖于一系列精心设计的数据结构。这些结构体不仅需要存储网络数据的元信息,还需支持复杂的协议逻辑(如路由、分片、安全策略等)。本文聚焦两个核心结构体 struct inet_skb_parm 和 struct ip_options,解析它们的设计原理、功…...

oracle 数据库查询指定用户下每个表占用空间的大小,倒序显示

oracle 查询指定用户下每个表占用空间的大小&#xff0c;倒序显示 使用场景&#xff1a;数据分析&#xff1b;导出医院正式库到开发环境时&#xff0c;查询出占用表空间高的业务表、导出时排除该表 在Oracle数据库中&#xff0c;要查询指定用户下每个表占用空间的大小并以倒序…...

Missashe考研日记-day29

Missashe考研日记-day29 1 专业课408 学习时间&#xff1a;3h学习内容&#xff1a; 今天先是把虚拟存储剩余的课听完了&#xff0c;然后就是做课后选择题&#xff0c;57道&#xff0c;已经接受了OS课后题尤其多的事实了。解决并且理解完习题之后就开始预习文件管理的内容&…...

【AI】【MCP】搭建私人王炸MCP自动化工作流

目录 一、什么是MCP 二、MCP大集合 三、准备工作 3.1 安装node.js 3.2 安装vscode 3.3 安装cline插件 3.3.1 安装 3.3.2 配置Cline 四、配置MCP服务 4.1 Search-mcp服务 4.2 playwright-mcp 服务 前言&#xff1a;梦想组合&#xff0c;轻松办公&#xff0c;告别手动&a…...

多元函数微分之传统方法和全微分法

一、传统方法 使用链式法则&#xff0c;先对中间变量&#xff08;如 u,v&#xff09;求偏导&#xff0c;再乘以中间变量对最终变量&#xff08;如 x,y&#xff09;的偏导。 二、全微分法 基于全微分形式不变性&#xff0c;直接对 zf(u,v) 求全微分 dz&#xff0c;再代入 du 和…...

新手SEO基础优化全解析

内容概要 对于刚接触SEO的新手而言&#xff0c;系统化理解优化逻辑是避免无效操作的关键。本文将从基础概念入手&#xff0c;逐步拆解搜索引擎排名的影响要素&#xff0c;围绕关键词分析、技术优化、内容策略三大核心模块&#xff0c;提供可落地的操作框架。通过结合工具使用说…...

MATLAB退火算法和遗传算法解决旅行商问题

模拟退火算法和遗传算法都是常用于解决旅行商问题&#xff08;TSP&#xff09;的优化算法&#xff0c;它们在原理、搜索方式、收敛速度和适用场景等方面存在一些区别&#xff1a; 原理 模拟退火算法&#xff1a;模拟退火算法的灵感来源于固体退火原理。固体在加热后缓慢冷却时…...

喜马拉雅卖身腾讯音乐:在线音频独立时代的终结

坦白说,这条消息一出来,喜马拉雅被卖掉不太奇怪,但是腾讯音乐会收购,还是有点意外。 喜马拉雅之前一度被称为中国版Audible平台,在过去几年里,活生生地把一手好牌打得稀烂。如今走到“卖身”这一步,既是无奈,也是必然。 简单回顾一下背景: 2012年,喜马拉雅成立,一…...

简单理解https与http

都是超文本传输协议&#xff0c;一个安全一个不安全&#xff0c;名字长的安全&#xff0c;名字短的不安全。 安全与不安全是居于什么分别的&#xff1f; 通过加密 http无加密。 httpshttp SSL/TSL&#xff08;加密&#xff09;来保障数据安全。加密传输 身份验证 SSL/TLS…...

打造即插即用的企业级云原生平台——KubeSphere 4.1 扩展组件在生产环境的价值全解

目录 打造即插即用的企业级云原生平台——KubeSphere 4.1 扩展组件在生产环境的价值全解 1. 可观测体系&#xff1a;WhizardTelemetry 全家桶 2. 平台与多集群治理 3. CI/CD 与交付效率 4. 网络与流量入口 5. 安全与合规 6. 存储与数据保护 7. 平台集成优势 结语 打造…...

配置扩展ACL

1.扩展ACL简介&#xff1a; 扩展ACL可以更精确地控制基于源IP地址、目标IP地址、协议类型和端口号的流量。 2.配置背景&#xff1a; 为了实现公司内部只能使用FTP服务器传输文件并关闭其他所有服务和端口的需求&#xff0c;可以通过配置访问控制列表&#xff08;ACL&#xf…...

根据用户出生日期计算年龄

public static int calculateAgeFromDate(Date birthDate) { // 将 Date 转换为 LocalDate&#xff08;默认时区&#xff09; LocalDate birthLocalDate birthDate.toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate(); // 获取当前日期LocalDate currentDate Local…...