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

CurrentHashMap的整体系统介绍及Java内存模型(JVM)介绍

当我们提到ConurrentHashMap时,先想到的就是HashMap不是线程安全的:

在多个线程共同操作HashMap时,会出现一个数据不一致的问题。

ConcurrentHashMap是HashMap的线程安全版本。

它通过在相应的方法上加锁,来保证多线程情况下的数据一致性。

hashmap导致数据不一致的原因?

数据不一致问题的表象有两种情况:

1.写-读冲突:一个线程修改后,另一个线程读到的不是最新的数据。

2.写-写冲突:两个线程同时修改数据,发生数据覆盖的情况。

原因是Java内存模型(JVM)的一些相关规定。

Java内存模型(JVM)

Java内存模型将内存分为两种,主内存工作内存。

并且规定,所有的变量都存储在主内存中(不包括局部变量与方法参数)。

主内存中的变量是所有线程共享的。

每个线程都有自己的工作内存,存储的是当前线程所使用到的变量值。主内存变量中的一个副本数据。

线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。

不同线程间无法直接访问对方工作内存中的变量。

线程间变量值的传递需要通过主内存实现。

这样规定的原因:

是为了屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。

关于各种硬件间的内存访问差异

CPU,内存,IO设备都在不断迭代,不断朝着更快的方向努力,但三者的速度是有差异的。

CPU最快,内存其次,IO设备(硬盘)最慢。

为了合理利用CPU的高性能,平衡三者间的速度差异,计算机体系结构,操作系统,编译系统都做了贡献,主要体现为:

  • CPU增加了缓存,以平衡与内存的速度差异,

这样CPU运算时所需要的变量,优先会从缓存中读取。

缓存没有时,会从主内存中加载并缓存。如下图所示:

image-20250509163155756

事物都是有两面性的,缓存提高了CPU的运算速度,也带来了相应的问题:

当多个线程在不同的CPU上运行并访问同一个变量时,由于缓存的存在,可能读取不到做最新的值,也就是可见性问题。

可见性指的是一个线程对共享变量的修改,另一个线程能够立刻看到,被称为可见性

  • 操作系统增加了进程线程,以时分复用CPU,进而均衡CPU与IO设备的速度差异

操作系统通过任务的一个切换来减少CPU的等待时间,从而提高效率。

任务切换的时间,可能是发生在任何一条CPU指令执行完之后。

但是我们平时使用的编程语言,如C,Java,Python等都是高级语言,高级语言转换成CPU指令时,一条指令可能对应多条CPU指令。 相当于1=n,这是违背我们直觉的地方。

所以问题来了,著名的count+=1问题就是这个原因。也就是原子性问题。

我们把一个或多个操作在CPU执行的过程中不被中断的特性为原子性。(这里的操作是指我们高级语言中相应的一些操作)

  • 编译程序优化指令执行次序,使得缓存能够得到更加合理的利用。

指令重排序可以提高了缓存的利用率,同样也带来了有序性问题

也就是单例模式问题

重排序提高缓存利用率的例子:

在平时写代码时,经常会在方法内部的开始位置,把这个方法用到的变量全部声明了一遍。缓存的容量是有限的,声明的变量多的时候 前面的变量可能就会在缓存中失效 。

接下来再写业务时,用到了最先声明的变量 然后发现在缓存中已经失效了,需要重新的去主内存进行加载。

所以指令重排序可以看成编译器对我们写的代码进行的一个优化。就类似于让变量都能用上,不至于等到失效在使用。

所以要想实现在各种平台都能达到一直的内存访问效果,就需要解决硬件和操作系统之间产生的问题:

1.CPU增加缓存最后导致的可见性问题

2.操作系统增加了线程,进程之后出现的原子性问题

3.指令重排序导致的有序性问题

Java内存模型如何解决三个问题?

原子性问题解决方案

  • JVM定义了8种操作来完成主内存与工作内存之间的数据交互,虚拟机在实现时需要保证每一种操作都是原子的,不可再分的。

Java中基本数据类型的访问、读写都是具备原子性的(long和Double除外),更大的原子性保证:Java提供了synchronized关键字(synchronized的字节码指令monitorenter和monitorexit来隐式的使用了lock和unlock操作),在synchronized块之间的操作也具备原子性。

八种操作: lock,unlock,read,load,assign,use,store,write

CAS(乐观锁),比较并替换,(Compare And Swap),CAS是一条CPU的原子指令(即cmpxchg指令),Java中的Unsafe类提供了相应的CAS方法,如(compareAndSwapXXX)底层实现即为CPU指令cmpxchg,从而保证操作的原子性。

可见性问题与有序性问题解决方案

  • JVM定义了Happens-Before原则来解决内存的不可见性与重排序的问题。

Happens-Before规则约束了编译器的优化行为,虽允许编译器优化,但是要求编译器优化后要遵守Happens-Before规则。

Happens-Before规则:

对于两个操作A和B,这两个操作可以在不同的线程中执行,如果A Happens-Before B,那么可以保证,当A操作执行完后,A操作的执行结果对B操作时可见的。

8种Happens-Before规则

程序次序规则、锁定规则、volatile变量规则、线程启动规则、线程终止规则、线程中断规则、对象终结原则、传递性原则。

volatile变量规则(重点):对一个volatile变量的写操作先行发生于后面的这个变量的读操作。

hashmap导致数据不一致的解决方案

常规思路是加锁,但是锁的存在会大大影响性能,所以提升性能的关键就是减少锁的粒度,以及找出哪些操作可以无锁化

对于写操作:涉及到对数据的改动,需要加锁,这只能尽量减少锁的粒度。

对于读操作:确保数据改动不会出错之后,读操作就相对好办;主要考虑的能不能读到另外一个线程对数据的一个改动(一致性)(等待写操作的完成)

这时就有三种情况:

  1. 强一致性 : 读写都加锁,类似于串行化,这样可以保证读到最新的数据,但性能过低

  2. 顺序一致性 : 变量使用volatile关键字修饰

  3. 弱一致性 : 读不加锁

对应方案:

  1. 强一致性 使用synchronized 修饰方法或者代码块,来保证代码块或方法的一致性,可见性(串行,即有序性),性能较低

  2. 顺序一致性 : 使用volatile关键字修饰变量,volatile 可以保证一个共享变量的可见性以及禁止指令的重排序

  3. 弱一致性: 使用CAS,CAS操作可以保证一个共享变量的原子操作。

我们可以去读一下ConcurrentHashMap的源码,

可以发现代码中一会使用CAS,一会使用synchronized,让人摸不清,为什么呢?

这是因为在高级语言中一条语句往往需要多条CPU指令完成

而Java中基本数据类型的访问、读写都具备原子性(long和Double除外),其他大部分不是原子性操作,

就比如在new一个对象时,就不是一个原子性操作,它需要三步才能完成,分配内存,初始化对象,将对象赋值给变量。

所以在创建数组的时候,除了使用synchronized外,CAS是不能保证原子性的,CAS只是CPU的一条指令,他不能保证多个指令的原子性,但是我们可以参考AQS,使用CAS锁一个基本类型的变量,其他线程进行自旋。

其次,synchronized锁需要一个对象,当数组的元素为null时,是无法使用synchronized锁的,所以此时使用的就是CAS操作来保证赋值的原子性。

以及底层的数组table已经被volatile修饰,但是数组元素的修改却不能保证可见性

明明volatile保证共享变量的可见性,为什么数组元素的修改却不能保证可见性呢?

原因:

volatile保证共享变量的可见性,但是如果该变量是一个对象的引用,那么volatile此时指的就是对象引用的可见性。

而在Java中,数组也是一个对象,当使用volatile来修饰数组arr时,代表的是arr的引用具有可见性,即arr的引用地址修改了之后,其他线程是可见的,但是无法保证数组内的元素具有可见性。

HashTable与ConcurrentHashMap

Hashtable

前置知识:在JDK1.0时,加锁只有synchronized一种方法,synchronized是重量级锁(需要去CPU申请锁)

底层结构:数组+链表 链表使用头插法 定位数组下标使用取余操作

线程安全: 使用synchronized来保证线程安全,在所有的方法上都加了synchronized关键字,即使用一把全局锁来同步不同线程间的并发访问(锁住整个table结构),性能较低。

相关操作: put,get,remove,size方法体上都添加synchronized关键字,扩容逻辑在put方法内发生,也是线程安全的

优点:实现简单

缺点:一个线程在插入数据时,其他线程不能读写,并发效率低下

ConcurrentHashMap(JDK1.5)

在JDK1.5时引入,此时Java内存模型已经成熟完善,在此基础上开发了java.util.concurrent包,ConcurrentHashMap随着JUC包一起引入JDK,同时引入了AQS,实现了ReentrantLock

底层结构:数组+链表 链表使用头插法 定位下标使用&运算

线程安全:使用分段锁的思想,其内部是一个Segment数组,Segment继承了ReentrantLock(可重复锁),即Segment自身就是一个锁。

Segment内部有一个HashEntry数组(Segment有点类似HashTable),每个HashEntry是一个链表结构的元素,一把锁只锁住容器中的一部分数据,多线程访问容器中里不同数据段的数据,就不会存在锁竞争,提高并发访问率

相关操作:调用put方法时,当前的segment会将自己锁住,此时其他线程无法操作这个segment,但不会影响到其他segment的操作。

调用get方法时,使用unsafe.getObjectVolatile方法获取节点;底层使用C++的volatile来实现Java中的volatile效果(保证共享变量的可见性(一个线程对共享变量的修改,另一个线程能够立刻看到))

调用remove方法时,当前的segment会将自己锁住。

put,get,remove操作都是在单个Segment上进行的,size操作是在多个segment进行的

size方法采用了一种比较巧妙的方式,来尽量避免对所有的Segment都加锁。

每个Segment都有一个modCount 变量,代表的是对Segment中元素的数量造成影响的操作次数。这个值只增不减。

size 操作就是遍历了两次Segment,每次记录Segment 的modCount值,然后将两次的modCount进行比较,如果相同,则表示期间没有发生过写入操作,就将原先遍历的结果返回。如果不相同,则把这个过程再重复做一次,如果再不同,则就需要将所有的Segment都锁住,然后一个一个遍历。

扩容操作,发生在put方法内部,跟put方法使用的是同一个锁.

扩容不会增加Segment的数量,只会增加Segment中链表数组的容量大小

这样的好处是扩容过程不需要对整个ConcurrentHashMaprehash,只需要对Segment里面的元素做一个rehash即可。这样就不会去影响其他的segment里面的元素。

优点:每次只锁住一部分数据,访问不同数据段的数据,不会存在锁竞争。提高了并发访问率;

扩容只针segment内部的HashEntry数组进行扩容,不影响其他segment内部的HashEntry数组。

缺点:定位一个元素,需要经过两次hash操作。 当某个segment很大时,类似Hashtable,性能会下降。

比较浪费内存空间(因为每个segment内部的HashEntry数组是不连续的)

拓展:

在JDK6中,针对synchronized做了大量的优化,引入了轻量级锁偏向锁。性能与ReentrantLock已相差无几,甚至synchronized的自动释放锁会更好用。

Java官方表示,在多线程环境下不建议使用HashMap。

随着互联网的快速发展,业务场景随之更加复杂,很多人在使用多线程的情况下使用HashMap的时候,结果导致cpu100%的情况。

主要原因:HashMap的链表使用的是头插法,在多线程的情况下触发扩容,链表可能会形成一个死循环。

在JDK8中也做了相应的优化,将头插法改为尾插法,引入了红黑树,来优化链表过长导致的查询速度变慢。

连带着ConcurrentHashMap也做了相应的修复,使得ConcurrentHashMap与HashMap的结构更加统一。

ConcurrentHashMap(JDK8之后)

image-20250509190726003

由类图可知,ConcurrentHashMap中有四种类型的节点,四种类型的节点的用途不同。

  • Node节点是ConcurrentHashMap中存储数据的最基本结构,也是其他类型节点的父类,他可以用来构建链表。hash值>=0

  • TreeNode节点主要用来构造红黑树以及存储数据hash值>=0

  • TreeBin节点是红黑树的代理节点,不存储数据,他的Hash值是一个固定值-2

  • ForWardingNode节点,表示的是底层数组table正在扩容,当前节点的数据已经迁移完毕,不存储数据,hash值也是固定值-1

注意事项:TreeBin为什么是红黑树的代理节点?

因为在向红黑树添加数据或删除数据时可能会触发红黑树的自平衡,根节点可能会被子节点替代,如果此时有线程来红黑树读取数据,可能会出现读取不到数据的情况。

而红黑树的查找是从根节点开始遍历的,当根节点变成子节点时,作为根节点的左子树或者右子树可能是不被遍历的。

ConcurrentHashMap的get方法是没有使用锁的,不可能通过加锁来保证强一致性,而红黑树的并发操作需要加上一层锁来保证在红黑树自平衡时的读操作没有问题。这就是TreeBin的工作。

TreeBin重要属性:

  • root:指向的是红黑树的根节点

  • first:指向的是双向链表,也就是所有的TreeNode节点构成的一个双向链表

  • lockState:用于实现基于CAS的读写锁。

总结:对红黑树添加或删除数据的整体操作:

首先在最外层加上synchronized同步锁,然后再红黑树自平衡时加上lockState的写锁。

当由线程来读红黑树的时候,会先判断此时是否有线程持有写锁或者是否有线程在等待获取写锁,如果有的话,读线程直接读取双向链表,否则会加上lockState的读锁。然后读取红黑树的数据,从而来保证读操作不被阻塞以及它的正确性。

双向链表的作用:

  • 读操作会来读取链表上的数据。

  • 在扩容时,会遍历双向链表,根据hash值判断是放在新数组的高位还是低位。

底层结构:数组+链表+红黑树 链表使用尾插法 定位下标使用 & 运算

线程安全:消了分段锁的设计,1取而代之的是通过 cas 操作和 synchronized 关键字来保证并发更新的安全。

Synchronized只是用于锁住链表或者红黑树的第一个节点,只要没有Hash冲突,就不存在并发问题,效率也就大大的提升。

相关操作:

put方法,使用cas + synchronized 来保证线程安全.

get方法,没有使用加锁,使用的是Unsafe.getObjectVolatile方法获取数据。保证数据的可见性。

remove方法、使用synchronized 来保证线程安全。

size方法(难点):主要是LongAdder的思想进行的累加计算。

扩容操作(难点):扩容操作发生在数据添加成功之后,并且支持多个线程。

优点:锁粒度更精细,性能更强

缺点:实现更加复杂。

希望对大家有所帮助!

相关文章:

CurrentHashMap的整体系统介绍及Java内存模型(JVM)介绍

当我们提到ConurrentHashMap时,先想到的就是HashMap不是线程安全的: 在多个线程共同操作HashMap时,会出现一个数据不一致的问题。 ConcurrentHashMap是HashMap的线程安全版本。 它通过在相应的方法上加锁,来保证多线程情况下的…...

手撕红黑树的 左旋 与 右旋

一、为什么需要旋转? 在红黑树中,插入或删除节点可能会破坏其五条性质,比如高度不平衡或连续红节点。 为了恢复红黑性质,我们采用局部旋转来“调整树形结构”,保持平衡。 二、旋转本质是“局部变形” 左旋和右旋不会…...

Java——反射

目录 5 反射 5 反射 类信息:方法、变量、构造器、继承和实现的类或接口。反射:反射是 Java 中一项强大的特性,它赋予了程序在运行时动态获取类的信息,并能够调用类的方法、访问类的字段以及操作构造函数等的能力。通过反射&#…...

一文了解Python中的requests库:网络交互的基础

目录 1. 前言 2. requests库的基本概念 3. requests库的适应场景 4. requests库的基本使用 4.1 安装requests 4.2 发送第一个请求 4.3 常见HTTP请求方法 4.4 响应对象的属性 4.5 发送带参数的请求 4.6 处理请求和响应 5. 高级功能 5.1 文件上传 5.2 会话对象 5.3…...

基于大模型预测的足月胎膜早破行阴道分娩全流程研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与方法 1.3 研究创新点 二、胎膜早破(足月)行阴道分娩概述 2.1 胎膜早破定义与分类 2.2 足月胎膜早破行阴道分娩的现状与挑战 2.3 大模型预测引入的必要性 三、大模型预测原理与技术 3.1 大模型介绍 3.2 数据收集与…...

ISP流程介绍(Raw格式阶段)

一、ISP之DPC DPC(Defective Pixel Correction)也就是坏点矫正,在sensor接收光信号,并做光电转换之后。 这一步设计的意义在于:摄像头sensor的感光元件通常很多会存在一些工艺缺陷缺陷,让图像上某些像素无法正常收集到需要的光信号…...

Codeforces Round 1023 (Div. 2)

Dashboard - Codeforces Round 1023 (Div. 2) - Codeforces 一个构造问题&#xff0c;我把最大的数放在一个数组&#xff0c;其余数放在另一个数组&#xff0c;就能保证gcd不同 来看代码&#xff1a; #include <bits/stdc.h> using namespace std;int main() {int t;ci…...

按位宽提取十六进制值

需求&#xff1a;给出一个十六进制值&#xff0c;要求提取high和low位之间的值。比如16ha0f0&#xff0c;这是一个16bit宽的十六进制数0xa0f0&#xff0c;提取[15:12]范围内的值。 def extract_bits(value, high, low):"""从 value 中提取 [high:low] 位的值:p…...

Android设备序列号获取方式全解析

Android设备序列号获取方式全解析 前言 在Android开发中&#xff0c;获取设备序列号&#xff08;SN&#xff09;是设备管理类应用常见的需求。但不同厂商设备获取方式存在差异&#xff0c;且Android系统版本升级也带来了API变化。本文将系统梳理7种主流序列号获取方式&#x…...

Spring框架(1)

Spring框架是Java企业级开发中最受欢迎的框架之一&#xff0c;它通过简化开发流程、降低耦合度&#xff0c;让开发者能够更专注于业务逻辑的实现。本文将带你了解Spring框架的核心概念和基本用法。 一、Spring框架简介 Spring是一个轻量级的开源Java开发框架&#xff0c;由Ro…...

软件安全(二)优化shellcode

我们在上一节课中所写的shellcode&#xff0c;其中使用到的相关的API是通过写入其内存地址来实现调用。这种方法具有局限性&#xff0c;如切换其他的操作系统API的内存地址就会发生变化&#xff0c;从而无法正常调用。 所谓的shellcode不过是在目标程序中加一个区段使得程序可…...

前端使用腾讯地图api实现定位功能

1.配置key 申请地址&#xff1a; https://lbs.qq.com/dev/console/key/manage 2.在项目中引入jssdk <script type"text/javascript" src"https://apis.map.qq.com/tools/geolocation/min?keykey&referermyapp"></script>使用 const g…...

单片机-STM32部分:10、串口UART

飞书文档https://x509p6c8to.feishu.cn/wiki/W7ZGwKJCeiGjqmkvTpJcjT2HnNf 串口说明 电平标准是数据1和数据0的表达方式&#xff0c;是传输线缆中人为规定的电压与数据的对应关系&#xff0c;串口常用的电平标准有如下三种&#xff1a; TTL电平&#xff1a;3.3V或5V表示1&am…...

STM32外设-串口UART

STM32外设-串口UART 一&#xff0c;串口简介二&#xff0c;串口基础概念1&#xff0c;什么是同步和异步/UART与USART对比2&#xff0c;串行与并行3&#xff0c;波特率 (Baud Rate)4&#xff0c;数据帧 (Data Frame)5&#xff0c;TX 和 RX 三&#xff0c;硬件连接1&#xff0c;u…...

《工业计算机硬件技术支持手册》适用于哪些人群?

《工业计算机硬件技术支持手册》于2024年出版&#xff0c;主要讲当前正在应用的最新计算硬件技术。包括计算机各种功能接口、扩展总线、各种国际通行的板型规格等等。书中引用的数据&#xff0c;全部来自国际行业技术规范&#xff0c;书中还融入了作者几十年的工作经验和操作技…...

element-ui时间线样式修改

element-ui时间线样式修改 前两天公司给了一个需求 要求如下图所示 需求是时间在步骤条左边,看了element-ui的文档 发现并没有参数可以设置时间在步骤条的左边 那没办法 只能自己想一想办法了 首先想到的是用样式直接改变 活不多说 直接搞 第一步 选中时间这个元素 发现了这个类…...

动态规划之背包问题:组合优化中的经典NP挑战

背包问题概念&#xff1a; 背包问题是一种经典的组合优化的NP问题&#xff0c;在计算机科学、运筹学等领域有着广泛的应用。 问题可以简单的描述为&#xff1a; 假设有一个容量为C的背包和n个物品&#xff0c;每个物品i都有重量w[i]和价值v[i]。目标是选择一些物品放入背包&…...

JavaScript 基础

JS概念 JS基础概念 JS是一种运行在客户端(浏览器)的编程语言, 实现人机交换结果 作用: 网页特效表单验证数据交互服务端编程(node.js) JS的组成 ECMAScript—javaScript语言基础Web APIs—(DOM: 页面文档对象模型)(BOM: 浏览器对象模型) JS书写 位置 内部: 写到< /body…...

Vibe Coding: 优点与缺点

如果你最近在开发圈子里,你很可能听说过这个新趋势"vibe coding"(氛围编程)。 我只能说我对此感受复杂。以下是原因。 优势 在构建新项目时,靠着氛围编程达到成功感觉很自由!但对于遗留代码来说情况就不同了,尽管也不是不可能。 实时反馈和快速迭代 Cursor(…...

小动物听力评价系统基本原理简析

小动物听力评价系统是用于评估小动物听力功能的专业设备&#xff0c;以下从系统组成、工作原理、评价方法等方面为你介绍&#xff1a; 一 系统组成 声音刺激模块&#xff1a;能产生不同频率、强度和类型的声音信号&#xff0c;如纯音、啭音、短声等&#xff0c;以刺激小动物的听…...

spark缓存-persist

存储级别指定 persist&#xff1a;可以通过传入 StorageLevel 参数来指定不同的持久化级别。常见的持久化级别有&#xff1a; MEMORY_ONLY&#xff1a;将 RDD 以 Java 对象的形式存储在 JVM 的内存中。若内存不足&#xff0c;部分分区将不会被缓存&#xff0c;需要时会重新计算…...

树初步 #1(插排串联 - 辽宁省2024CCPC)

树初步 数的基础内容可以看看树基础 - OI Wiki里面的讲解&#xff0c;对一些操作的基础概念介绍的很清楚&#xff1b; 下面直接来看例题&#xff1a; 插排串联 - 辽宁省CCPC 题目大意 给定一个n1个节点的有根数&#xff1b; 根节点&#xff08;0号&#xff09;是插座&…...

CDGP重点知识梳理(82个)

目 录 考点分布 考试要求 第一章 数据管理-5%...

shell脚本基础详细学习(更新中)

shell简单介绍 Shell不仅仅是充当用户与UNIX或者localhost交互的角色&#xff0c;还可以作为一种程序设计 语言来使用。通过Shell编程&#xff0c;可以实现许多非常实用的功能&#xff0c;提高系统管理的自动化水平。 如果有一系列经常需要使用的命令&#xff0c;把它存储在一…...

记录一下学习kafka的使用以及思路

下面这是kafka的依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-stream-kafka</artifactId></dependency> 我在学习的时候直接导入是没有导入成功的&#xff0c;我猜测大概的原因是我本…...

AT9880B北斗单模卫星定位SOC芯片

AT9880B是一款高性能北斗单模卫星导航接收机SOC单芯片&#xff0c;芯片集成射频前端和数字基带、北斗多频卫星信号处理引擎、电源管理功能。芯片支持接收中国北斗二号和北斗三号&#xff0c;支持接收B1I、B1C、B2I、B3I、B2a和 B2b等频点信号。 主要特性&#xff1a; 支持北斗…...

李沐《动手学深度学习》 | 多层感知机

文章目录 感知机模型《深度学习入门》的解释训练感知机损失函数的选择感知机的收敛定理&#xff1a;什么时候能够停下来&#xff0c;是不是真的可以停下来感知机的不足 多层感知模型案例引入隐藏层从线性到非线性单隐藏层-单分类案例多隐藏层 激活函数softmax函数溢出的问题 多…...

vue数据可视化开发常用库

一、常用数据可视化库 1. ECharts 特点&#xff1a;功能强大&#xff0c;支持多种图表类型&#xff0c;社区活跃。适用场景&#xff1a;复杂图表、大数据量、3D 可视化。安装&#xff1a;npm install echarts示例&#xff1a;<template><div ref"chart" c…...

CAN转ModbusTCP网关:破解电池生产线设备协议壁垒,实现全链路智能互联

在电池生产的现代工艺中&#xff0c;自动化和信息化水平的提高是提升产能、保障品质与安全的关键。CAN 协议作为一种广泛应用于汽车、工业控制等领域的串行通信协议&#xff0c;它以其高可靠性和强实时性而受到企业的青睐。而在众多工业通讯协议中&#xff0c;ModbusTCP作为一种…...

更新 / 安装 Nvidia Driver 驱动 - Ubuntu - 2

如果按更新 / 安装 Nvidia Driver 驱动 - Ubuntu-CSDN博客中的步骤操作后问题依旧&#xff0c;则查看过程中的提示信息。 如果发现有“Use sudo apt autoremove to remove them.”&#xff0c;则执行&#xff1a; #sudo apt autoremove #nvidia-smi...

技术分享 | 如何在2k0300(LoongArch架构)处理器上跑通qt开发流程

近期迅为售后团队反馈&#xff0c;许多用户咨询&#xff1a;2K0300处理器采用了LA264处理器核&#xff0c;若要在该处理器上运行Qt程序&#xff0c;由于架构发生了变化&#xff0c;其使用方法是否仍与ARM平台保持一致&#xff1f; 单纯回答‘一致’或‘不一致’缺乏说服力&…...

ubuntu 24.04 error: cannot uninstall blinker 1.7.0, record file not found. hint

最近在打python3.12的镜像&#xff0c;安装browser-gym的核心库&#xff0c;编译一个使用browswer agents的环境&#xff0c;然后出现了下面的问题&#xff1a; error: cannot uninstall blinker 1.7.0, record file not found. hint: the package was installed by debian.系…...

学习记录:DAY28

DispatcherController 功能完善与接口文档编写 前言 没什么动力说废话了。 今天来完善 DispatcherController 的功能&#xff0c;然后写写接口文档。 日程 早上&#xff1a;本来只有早八&#xff0c;但是早上摸鱼了&#xff0c;罪过罪过。下午&#xff1a;把 DispatcherContro…...

C# 的异步任务中, 如何暂停, 继续,停止任务

namespace taskTest {using System;using System.Threading;using System.Threading.Tasks;public class MyService{private Task? workTask;private readonly SemaphoreSlim semaphore new SemaphoreSlim(0, 1); // 初始为 0&#xff0c;Start() 启动时手动放行private read…...

html object标签介绍(用于嵌入外部资源通用标签)(已不推荐使用deprecated,建议使用img、video、audio标签)

文章目录 HTML <object> 标签详解基本语法与核心属性关键属性解析1. **data**2. **type**3. **width & height**4. **name** 嵌入不同类型的资源1. **嵌入图像**2. **嵌入音频**3. **嵌入视频**4. **嵌入 PDF** 参数传递与回退内容**参数&#xff08;<param>&a…...

专题练习1

优化: 找101-200的质数: 开发验证码: 解密数字 抽奖 优化 彩票...

Uniapp编写微信小程序,使用canvas进行绘图

一、canvas文档&#xff1a; https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial 二、数据绘制&#xff08;单位是像素&#xff09;&#xff1a; 1、绘制文本&#xff1a; 文字的长度超过设置的最大宽度&#xff0c;文字会缩在一起 ① 填充文本&#xf…...

Java高频基础面试题

Java高频基础面试题 Java基础 Java的特点是什么&#xff1f; 面向对象平台无关性&#xff08;“一次编写&#xff0c;到处运行”&#xff09;支持多线程自动内存管理&#xff08;垃圾回收&#xff09;安全性丰富的类库 JDK、JRE和JVM的区别 JDK (Java Development Kit): Java…...

U9C-SQL-采购订单视图

U9C-SQL-采购订单视图 SELECTpo.ID,CONVERT ( VARCHAR ( 10 ), po.CreatedOn, 23 ) AS 签订日期,org.Name AS 甲方,po.DocNo AS 单号,item.Code AS 料号,item.Name AS 品名,item.SPECS AS 规格,item.DescFlexField_PrivateDescSeg1 AS 图号,item.DescFlexField_PrivateDescSeg2…...

HTML字符串转换为React元素实现

HTML字符串安全转换为React元素的实现 一、背景介绍 介绍HTML字符串在Web开发中的常见场景。说明React中直接使用HTML字符串的局限性。提出将HTML字符串转换为React元素的需求。 二、首先必备的两个npm库&#xff1a;html-react-parser和dompurify 导入&#xff1a; pnpm i…...

全局异常未能正确捕获到对应的异常

自定义Validation验证器遇到的问题 抛出的异常没有能被指定的TaskValidException.class方法拦截到。故写这个原因 全局异常拦截只能拦截相同的异常。只能通过解析转入自定义的异常。自定义的异常继承的异常要是一家子的。如TaskValidException和ValidationException。这样就能在…...

LeetCode 解题思路 47(最长回文子串、最长公共子序列)

解题思路&#xff1a; dp 数组的含义&#xff1a; dp[i][j] 是否为回文子串。递推公式&#xff1a; dp[i][j] s.charAt(i) s.charAt(j) && dp[i 1][j - 1]。dp 数组初始化&#xff1a; 单字符 dp[i][i] true&#xff0c;双字符 dp[i][i 1] s.charAt(i) s.charA…...

P11369 [Ynoi2024] 弥留之国的爱丽丝(操作分块,DAG可达性trick)

真的神仙题。感觉学到了很多。 题意&#xff1a; 给你一张 n n n 个结点 m m m 条边的有向图&#xff0c;点编号为 1 , 2 , … , n 1,2,\dots,n 1,2,…,n。每条边的颜色为黑色或白色。一开始所有 m m m 条边都是黑色的。 你需要进行 q q q 次操作&#xff0c;有两种操作…...

NAT穿越

概述 IPSec协商是通过IKE完成--->ISAKMP协议完成--->由UDP封装&#xff0c;源目端口均为500。 NAT--->NAPT&#xff0c;同时转换IP和端口信息。 对端设备会查验收到的数据报文中的源IP和源端口&#xff0c;其中源IP可以设定为NAT转换后的IP&#xff0c;但是源端口无法…...

不黑文化艺术学社首席艺术家孙溟㠭浅析“雪渔派”

孙溟㠭浅析“雪渔派” 何震 字主臣 &#xff0c;长卿&#xff0c;号雪渔&#xff0c;安徽婺源&#xff08;今江西&#xff09;人&#xff0c;是明代著名的篆刻家和书法家&#xff0c;与文彭独树一帜&#xff0c;实现书法与刀法的统一。 云中白鹤 笑谭间气吐霓虹 边款 其篆刻吸…...

【Linux操作系统】第一弹——Linux基础篇

文章目录 &#x1f4a1; 一. Linux的基本常识&#x1fa94; 1.1 linux网络连接三种方式&#x1fa94;1.2 虚拟机的克隆&#x1fa94;1.3 虚拟机的快照&#x1fa94;1.4 虚拟机的迁移和删除&#x1fa94;1.5 vmtools工具 &#x1f4a1;二. Linux的目录结构&#x1fa94;2.1 Linu…...

“ES7+ React/Redux/React-Native snippets“常用快捷前缀

请注意&#xff0c;这是一个常用的列表&#xff0c;不是扩展提供的所有前缀。最完整和最新的列表请参考扩展的官方文档或在 VS Code 中查看扩展的详情页面。 React (通常用于 .js, .jsx, .ts, .tsx): rfce: React Functional Component with Export Defaultrafce: React Arro…...

selenium替代----playwright

安装 好处特点&#xff1a;这个东西不像selenium需要固定版本的驱动 pip config set global.index-url https://mirrors.aliyun.com/pypi/simplepip install --upgrade pippip install playwright playwright installplaywright install ffmpeg (处理音视频的)验证&#x…...

2025年社交APP安全防御指南:抵御DDoS与CC攻击的实战策略

2025年&#xff0c;社交APP的用户规模与业务复杂度持续增长&#xff0c;但随之而来的DDoS与CC攻击也愈发隐蔽和智能化。攻击者通过AI伪造用户行为、劫持物联网设备&#xff0c;甚至利用区块链漏洞发起混合攻击&#xff0c;对平台稳定性与用户数据安全构成严峻挑战。本文将结合最…...

PHP会话技术

第十六章-PHP会话技术 PHP会话技术是构建动态、个性化Web应用的核心机制之一&#xff0c;它通过跟踪用户在网站上的连续操作状态&#xff0c;实现了网页间的数据持久化交互。无论是电商平台的购物车信息保存、社交媒体的用户登录状态维持&#xff0c;还是表单数据的跨页面传递…...