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

JUC并发编程19 | 读写锁

有一些关于锁的面试题:

  1. 你知道 Java 里面有哪些锁?
  2. 读写锁的饥饿问题是什么?
  3. 有没有比读写锁更快的锁?
  4. StampedLock知道嘛?(邮戳锁/票据锁)
  5. ReentrantReadWriteLock 有锁降级机制?

ReentrantReadWriteLock

与 ReentrantLock 相比,ReentrantLock 实现了 Lock 接口,ReentrantReadWriteLock 实现了 ReadWriteLock 接口。对于ReentrantLock 它的 读读也是一个线程访问,浪费资源。ReentrantReadWriteLock 可以实现读读共享!

读写锁定义为:一个资源能被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程(读写互斥,读读共享)

class MyRescource {  // 资源类模拟缓存Map<String, String> map = new HashMap<>();// ========= ReentrantLock 等价于 ======== SynchronizedLock lock = new ReentrantLock();// ========= ReentrantReadWritLock =======读读共享ReadWriteLock readWriteLock = new ReentrantReadWriteLock();public void write(String key, String value) {lock.lock();try{System.out.println(Thread.currentThread().getName()+"\t正在写入。。。。");map.put(key,value);try {TimeUnit.MILLISECONDS.sleep(1000);System.out.println(Thread.currentThread().getName()+"\t完成写入。。。。");}catch (InterruptedException e){e.printStackTrace();}}finally {lock.unlock();}}public void readWriteWrite(String key, String value) {readWriteLock.writeLock().lock();try{System.out.println(Thread.currentThread().getName()+"\t正在写入。。。。");map.put(key,value);try {TimeUnit.MILLISECONDS.sleep(1000);System.out.println(Thread.currentThread().getName()+"\t完成写入。。。。");}catch (InterruptedException e){e.printStackTrace();}}finally {readWriteLock.writeLock().unlock();}}public void read(String key) {lock.lock();try{System.out.println(Thread.currentThread().getName()+"\t正在读入。。。。");String s = map.get(key);try {// 1. 暂停500毫秒// 2. 暂停2000毫秒,显式读锁没有完成之前,写锁无法获取锁TimeUnit.MILLISECONDS.sleep(2000);System.out.println(Thread.currentThread().getName()+"\t完成读入。。。。\t"+s);}catch (InterruptedException e){e.printStackTrace();}}finally {lock.unlock();}}public void readWriteRead(String key) {readWriteLock.readLock().lock();try{System.out.println(Thread.currentThread().getName()+"\t正在读入。。。。");String s = map.get(key);try {// 1. 暂停500毫秒// 2. 暂停2000毫秒,显式读锁没有完成之前,写锁无法获取锁TimeUnit.MILLISECONDS.sleep(2000);System.out.println(Thread.currentThread().getName()+"\t完成读入。。。。\t"+s);}catch (InterruptedException e){e.printStackTrace();}}finally {readWriteLock.readLock().unlock();}}
}public class ReentrantReadWriteLockDemo {public static void main(String[] args) {MyRescource myRescource = new MyRescource();for (int i = 0; i < 10; i++) {int finalI = i;new Thread(()->{// myRescource.write("key"+String.valueOf(finalI),"value"+String.valueOf(finalI));myRescource.readWriteWrite("key"+String.valueOf(finalI),"value"+String.valueOf(finalI));},String.valueOf(i)).start();}for (int i = 0; i < 10; i++) {int finalI = i;new Thread(()->{// myRescource.read("key"+String.valueOf(finalI));myRescource.readWriteRead("key"+String.valueOf(finalI));},String.valueOf(i)).start();}try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}// 显式读锁没有完成之前,写锁无法获取锁for (int i = 0; i < 3; i++) {int finalI = i;new Thread(()->{// myRescource.write("key"+String.valueOf(finalI),"value"+String.valueOf(finalI));myRescource.readWriteWrite("key"+String.valueOf(finalI),"value"+String.valueOf(finalI));},"新读写锁"+String.valueOf(i)).start();}}
}

锁降级

ReentrantReadWriteLock锁降级:将写入锁降级为读锁(类似Linux文件读写权限理解,就像写权限要高于读权限一样),锁的严苛程度变强叫做升级,反之叫做降级。

重进入:该锁支持重进入,以读写线程为例:读线程在获取了读锁之后,能够再次获取读锁。而写线程在获取了写锁之后能够再次获取写锁,同时也可以获取读锁。

锁降级:遵循获取写锁、获取读锁再释放写锁的次序,写锁能够降级成为读锁

写锁的降级,降级成为了读锁

  1. 如果同一个线程持有了写锁,在没有释放写锁的情况下,它还可以继续获得读锁。这就是写锁的降级,降级成为了读锁。
  2. 规则惯例,先获取写锁,然后获取读锁,再释放写锁的次序。
  3. 如果释放了写锁,那么就完全转换为读锁。

保证数据的一致性

/**
所降级遵循了获取写锁,在获取读锁,再释放写锁的次序,写锁能够降级为读锁。因为写的优先级比读高
如果一个线程占有了写锁,在不释放写锁的情况下,它还能占有读锁,即写锁降级为读锁
读没有完成时候写锁无法获得锁,只有在读锁读完才可以
*/
public void lockLevelDown(){ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();writeLock.lock();System.out.println("写入");readLock.lock();System.out.println("读入");writeLock.unlock();readLock.unlock();readLock.lock();System.out.println("读入");writeLock.lock();System.out.println("写入");readLock.unlock();writeLock.unlock();
}
/**
写入
读入
读入
*/

分析StampedLock,会发现它改进之处在于:

读的过程中也允许获取写锁介入(相当牛B,读和写两个操作也让你“共享”(注意引亏)),这样会守致戎们实的数掂趴可能个一以所以,需要额外的方法来判断读的过程中是否有写入,这是一种乐观的读锁。

显然乐观锁的并发效率更高,但一旦有小概率的写入导致读取的数据不一致,需要能检测出来,再读一遍就行。

为什么要锁降级?

锁降级的必要性1:

锁降级中读锁的获取是否必要呢?答案是必要的。主要是为了保证数据的可见性,如果当前线程不获取读锁而是直接释放写锁, 假设此刻另一个线程(记作线程T)获取了写锁并修改了数据,那么当前线程无法感知线程T的数据更新。如果当前线程获取读锁,即遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用数据并释放读锁之后,线程T才能获取写锁进行数据更新。

部分人读完上述话可能有些疑惑,针对上面黑体字那句话,为什么无法感知线程T的数据更新?我当前线程再次获取读锁的时候不是可以察觉到数据在主存中的变化吗? 我参考了一些资料,对该 “”数据可见性“” 有了另一种理解,理解是 当前线程为了保证数据的可见性,这是指线程自己更改了数据,自己应该要察觉到数据的变化,如果没有读锁,更改完数据之后线程T获取到了写锁并更改了数据,则当前线程读到的数据是线程T更改的,并不是自己更改的,当前线程并不知道是线程T修改了自己要读的(原来自己改的)数据,所以可能导致当前线程在执行后续代码的时候结果出错,这时就导致了数据的不可见,即当前线程并无法察觉到自己修改的值!

锁降级的必要性2:

为了提高程序执行性能,可能存在一个事务线程不希望自己的操作被别的线程中断,而这个事务操作可能分成多部分操作更新不同的数据(或表)甚至非常耗时。如果长时间用写锁独占,显然对于某些高响应的应用是不允许的,所以在完成部分写操作后,退而使用读锁降级,来允许响应其他进程的读操作。只有当全部事务完成后才真正释放锁。

StampedLock

邮戳锁、版本锁是比读写锁更快的锁。

StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中读写锁ReentrantReadWriteLock的优化。

stamp(戳记,long 类型):代表了锁的状态。当stamp返回零时,表示线程获取锁失败。并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值。

锁饥饿问题:ReentrantReadWriteLock实现了读写分离,但是一旦读操作比较多的时候,想要获取写锁就变得比较困难了,假如当前1000个线程,999个读,1个写,有可能999个读取线程长时间抢到了锁,那1个写线程就悲剧了因为当前有可能会一直存在读锁,而无法获得写锁,根本没机会写。

如何缓解锁饥饿问题:

  • 使用“公平”策略可以一定程度上缓解这个问题 new ReentrantReadWriteLock(true)
  • 但是“公平"策略是以牺牲系统吞吐量为代价

StampedLock 类的乐观读锁:对于短的制度代码段,使用乐观模式通常可以减少争用并提高吞吐量

ReentrantReadWriteLock

允许多个线程同时读,但是只允许一个线程写,在线程获取到写锁的时候,其他写操作和读操作都会处于阻塞状态,

读锁和写锁也是互斥的,所以在读的时候是不允许写的,读写锁比传统的synchronized速度要快很多,

原因就是在于ReentrantReadWriteLock支持读并发,读读可以共享

StampedLock横空出世

ReentrantReadWriteLock的读锁被占用的时候,其他线程尝试获取写锁的时候会被阻塞。

但是,StampedLock采取乐观获取锁后,其他线程尝试获取写锁时不会被阻塞,这其实是对读锁的优化,

所以,在获取乐观读锁后,还需要对结果进行校验。

StampedLock的特点

所有获得锁的方法,都返回一个邮戳(Stamp),Stamp为零表示获取失败,其余都表示成功

所有释放锁的方法,都需要一个邮戳(Stamp),这个Stamp必须是和成功获取锁时得到的Stamp一致

StampedLock 是不可重入的,危险(如果一个线程已经持有了写锁,再去获取写锁的话就会造成死锁)

StampedLock 有三种访问模式:

  1. Reading(读模式悲观):功能和ReentrantReadWriteLock 的读锁类似
  2. Writeing(写模式):功能和ReentrantReadWriteLock 的写锁类似
  3. Optimistic reading(乐观读模式):无锁机制,类似于数据库中的乐观锁,支持读写并发,很乐观认为读取时没人修改,假如被修改再实现升级为悲观读模式——读的过程中也允许获取写锁介入

邮戳读写锁的传统版本

public class StampedLockDemo {static int number = 37;static StampedLock stampedLock = new StampedLock();public void write(){long stamp = stampedLock.writeLock();System.out.println(Thread.currentThread().getName()+"\t 写线程准备修改。");try{number = number + 13;} finally {stampedLock.unlockWrite(stamp);}System.out.println(Thread.currentThread().getName()+"\t 写线程结束修改。");}public void read(){long stamp = stampedLock.readLock();System.out.println(Thread.currentThread().getName()+"\t 悲观读线程准备修改。..");try{for (int i = 0; i < 4; i++) {TimeUnit.SECONDS.sleep(1);System.out.println("读线程正在读取中");}int result = number;System.out.println(Thread.currentThread().getName()+"\t 悲观读线程结束修改。result = "+result);System.out.println("写线程没有修改成功,读锁时候写锁无法介入,传统读写互斥");} catch (InterruptedException e) {e.printStackTrace();} finally {stampedLock.unlockRead(stamp);}}public static void main(String[] args) {StampedLockDemo demo = new StampedLockDemo();new Thread(()->{demo.read();},"读线程").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{demo.write();},"写线程").start();}}
/**
读线程	 悲观读线程准备修改。..
读线程正在读取中
读线程正在读取中
读线程正在读取中
读线程正在读取中
读线程	 悲观读线程结束修改。result = 37
写线程没有修改成功,读锁时候写锁无法介入,传统读写互斥
写线程	 写线程准备修改。
写线程	 写线程结束修改。
*/

邮戳锁乐观版本

public class StampedLockDemo {static int number = 37;static StampedLock stampedLock = new StampedLock();public void write(){long stamp = stampedLock.writeLock();System.out.println(Thread.currentThread().getName()+"\t 写线程准备修改。");try{number = number + 13;} finally {stampedLock.unlockWrite(stamp);}System.out.println(Thread.currentThread().getName()+"\t 写线程结束修改。");}public void read(){long stamp = stampedLock.readLock();System.out.println(Thread.currentThread().getName()+"\t 悲观读线程准备修改。..");try{for (int i = 0; i < 4; i++) {TimeUnit.SECONDS.sleep(1);System.out.println("读线程正在读取中");}int result = number;System.out.println(Thread.currentThread().getName()+"\t 悲观读线程结束修改。result = "+result);System.out.println("写线程没有修改成功,读锁时候写锁无法介入,传统读写互斥");} catch (InterruptedException e) {e.printStackTrace();} finally {stampedLock.unlockRead(stamp);}}public void tryOptimisticRead(){long stamp = stampedLock.tryOptimisticRead();int result = number;System.out.println("4秒前stampedLock.validate方法值 (true无修改,false有修改)\t"+stampedLock.validate(stamp));for (int i = 0; i < 4; i++) {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"\t正在读取"+i+"秒,后stampedLock.validate方法值\t"+stampedLock.validate(stamp));}if (!stampedLock.validate(stamp)){System.out.println("有人修改------有写操作");stamp = stampedLock.readLock();try{System.out.println("从乐观读 升级为 悲观读");result = number;System.out.println("从新悲观读后result="+result);}finally {stampedLock.unlockRead(stamp);}}System.out.println(Thread.currentThread().getName()+"\t最后的值是"+result);}public static void main(String[] args) {StampedLockDemo demo = new StampedLockDemo();new Thread(()->{System.out.println(Thread.currentThread().getName()+"进入");demo.tryOptimisticRead();},"乐观读线程").start();try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{System.out.println(Thread.currentThread().getName()+"进入");demo.write();},"写线程").start();}
}
/**
乐观读线程进入
4秒前stampedLock.validate方法值 (true无修改,false有修改)	true
乐观读线程	正在读取0秒,后stampedLock.validate方法值	true
写线程进入
写线程	 写线程准备修改。
写线程	 写线程结束修改。
乐观读线程	正在读取1秒,后stampedLock.validate方法值	false
乐观读线程	正在读取2秒,后stampedLock.validate方法值	false
乐观读线程	正在读取3秒,后stampedLock.validate方法值	false
有人修改------有写操作
从乐观读 升级为 悲观读
从新悲观读后result=50
乐观读线程	最后的值是50
*/

邮戳锁的缺点:

  1. StampedLock 不支持重入,没有 Re 开头
  2. StampedLock 的悲观读锁和写作都不支持条件变量
  3. 使用StampedLock一定不要调用中断操作

相关文章:

JUC并发编程19 | 读写锁

有一些关于锁的面试题&#xff1a; 你知道 Java 里面有哪些锁&#xff1f;读写锁的饥饿问题是什么&#xff1f;有没有比读写锁更快的锁&#xff1f;StampedLock知道嘛&#xff1f;&#xff08;邮戳锁/票据锁&#xff09;ReentrantReadWriteLock 有锁降级机制&#xff1f; Ree…...

springboot_maven项目怎么引入mybatis

在pom.xml文件中添加mybatis和mybatis-spring-boot-starter的依赖 org.mybatis mybatis ${mybatis.version} org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis.spring.version} 配置mybatis 在application.properties&#xff08;或application.yml&#xff0…...

JAVA8的新特性——lambda表达式

JAVA8的新特性——lambda表达式 此处&#xff0c;我们首先对于Java8的一些特性作为一个简单介绍 Java 8是Java编程语言的一个重要版本&#xff0c;于2014年发布。Java 8引入了许多新特性和改进&#xff0c;以提高开发效率和性能。以下是Java 8的一些主要新特性&#xff1a; Lam…...

算法修炼之练气篇——练气六层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 前言&#xff1a;每天练习五道题&#xff0c;炼气篇大概会练习200道题左右&#xff0c;题目有C语言网上的题&#xff0c;也有洛谷上面的题&#xff0c;题目简单适合新手入门。&#xff08;代码都是命运之光自己写的…...

利用GPU并行计算beta-NTI,大幅减少群落构建计算时间

1 先说效果 18个样本&#xff0c;抽平到8500条序列&#xff0c;4344个OTUs&#xff0c;计算beta-NTI共花费时间如下。如果更好的显卡&#xff0c;更大的数据量&#xff0c;节约的时间应该更加可观。 GPU&#xff08;GTX1050&#xff09;&#xff1a;1分20秒 iCAMP包 的bNTIn.p(…...

Shiro框架漏洞分析与复现

Shiro简介 Apache Shiro是一款开源安全框架&#xff0c;提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用&#xff0c;同时也能提供健壮的安全性&#xff0c;可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。 1、Shiro反序列…...

(数字图像处理MATLAB+Python)第七章图像锐化-第一、二节:图像锐化概述和微分算子

文章目录 一&#xff1a;图像边缘分析二&#xff1a;一阶微分算子&#xff08;1&#xff09;梯度算子A&#xff1a;定义B&#xff1a;边缘检测C&#xff1a;示例D&#xff1a;程序 &#xff08;2&#xff09;Robert算子A&#xff1a;定义B&#xff1a;示例C&#xff1a;程序 &a…...

C# | 内存池

内存池 文章目录 内存池前言什么是内存池内存池的优点内存池的缺点 实现思路示例代码结束语 前言 在上一篇文章中&#xff0c;我们介绍了对象池的概念和实现方式。对象池通过重复利用对象&#xff0c;避免了频繁地创建和销毁对象&#xff0c;提高了系统的性能和稳定性。 今天我…...

程序设计入门——C语言2023年5月10日

程序设计入门——C语言 1、window下安装gcc 课程来源&#xff1a;链接: 浙江大学 翁恺 程序设计入门——C语言 学习日期&#xff1a;2023年5月10日 1、window下安装gcc 如果想让gcc在windows下运行&#xff0c;需要将gcc&#xff0c;及对于的lib包&#xff0c;都安装到window…...

【2023华为OD笔试必会25题--C语言版】《03 单入口空闲区域》——递归、数组、DFS

本专栏收录了华为OD 2022 Q4和2023Q1笔试题目,100分类别中的出现频率最高(至少出现100次)的25道,每篇文章包括原始题目 和 我亲自编写并在Visual Studio中运行成功的C语言代码。 仅供参考、启发使用,切不可照搬、照抄,查重倒是可以过,但后面的技术面试还是会暴露的。✨✨…...

Grafana安装、升级与备份(02)

一、安装Grafana软件包 Grafana部署非常简单,直接使用yum命令从官网拉到安装再启动就可以了,本次使用的grafana版本为9.5.0 官网下载地址:Download Grafana | Grafana Labs # wget yum install -y https://dl.grafana.com/oss/release/grafana-9.5.0-1.x86_64.rpm # yum …...

【2023华为OD笔试必会25题--C语言版】《10 相同数字的积木游戏》——数组

本专栏收录了华为OD 2022 Q4和2023Q1笔试题目,100分类别中的出现频率最高(至少出现100次)的25道,每篇文章包括原始题目 和 我亲自编写并在Visual Studio中运行成功的C语言代码。 仅供参考、启发使用,切不可照搬、照抄,查重倒是可以过,但后面的技术面试还是会暴露的。✨✨…...

awk命令编辑

awk工作原理 逐行读取文本&#xff0c;默认以空格或tab键分隔符进行分隔&#xff0c;将分隔所得的各个字段保存到内建变量中&#xff0c;并按模式或者条件执行编辑命令。 sed命令常用于一整行的处理&#xff0c;而awk比较倾向于将一行分成多个“字段”然后再进行处理。awk信息…...

Pinia和Vuex的区别

Pinia和Vuex都是Vue.js状态管理库 Pinia是一个轻量级的状态管理库&#xff0c;它专注于提供一个简单的API来管理应用程序的状态。 相比之下&#xff0c;Vuex是一个更完整的状态管理库&#xff0c;它提供了更多的功能&#xff0c;比如模块化、插件和严格模式等。 Pinia是基于V…...

《C++高并发服务器笔记——第四章Linux网络编程》

计算机网络等相关知识可以去小林coding进行巩固&#xff08;点击前往&#xff09; 《C高并发服务器笔记——第四章》 4.1、网络结构模式1.C/S结构①C/S结构简介②C/S结构优点③C/S结构缺点 2.B/S结构①B/S结构简介②B/S结构优点③B/S结构缺点 4.2和4.3、MAC地址、IP地址、端口…...

NFS服务器搭建(案例)

目录标题 第一个问题1.安装软件包2.进入配置文件进行定义&#xff0c;并创建对应的资源文件3.客户端进行挂载&#xff0c;并查看挂载信息&#xff0c;修改挂载权限4.客户端查看挂载的信息 第二个问题1.服务端配置文件进行定义&#xff0c;并创建对应资源文件2.客户端进行挂载3.…...

ubuntu 22.04 安装 Docker Desktop 及docker介绍

目录 一、Docker Desktop 安装 1、我们先去官网下载安装包 2、Install Docker Desktop on Ubuntu 3、Launch Docker Desktop 二、Docker 介绍 什么是docker 如何使用docker docker是如何工作的 docker build docker run docker pull 一、Docker Desktop 安装 1、我们先…...

微前端中的应用隔离是什么,一般是怎么实现的?

微前端中的应用隔离是什么&#xff0c;一般是怎么实现的? 前言一、iframe 隔离二、Web Components三、JavaScript 沙箱隔离四、Shadow DOM 隔离总结 前言 微前端中的应用隔离是指将不同的微前端应用程序隔离开来&#xff0c;以确保它们之间不会相互影响或干扰。这种隔离可以通…...

【python pandas】合并文件并剔除重复数据

1.背景 工作中需要处理多个文件&#xff0c;每个文件里面有重复的数据&#xff0c;剔除重复数据&#xff0c;保留最新的数据 2.代码&#xff1a; import pandas as pd import osdl [] #person_list是文件路径 for i in range(person_list_len):#把文件df全部集合进列表dldl.a…...

Spellman高压电源X射线发生器维修XRB160PN480X4593

spellman高压发生器维修VMX40P5X4629&#xff1b;Spellman X射线发生器维修X4593系列 X射线源维修。 Spellman所拥有的变频器架构可以使高压电源获得高利用率的效率和功率密度。固体密封的高压模块进一步减少了尺寸和重量。 基于表面贴装控制电路的数字信号处理器提供通讯接口…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...