Java性能调优 - 多线程性能调优
锁优化
Synchronized
在JDK1.6
中引入了分级锁机制来优化Synchronized
。当一个线程获取锁时
- 首先对象锁将成为一个偏向锁,这样做是为了优化同一线程重复获取锁,导致的用户态与内核态的切换问题;
- 其次如果有多个线程竞争锁资源,锁将会升级为轻量级锁,它适用于在
短时间内持有锁,且分锁有交替切换的场景
; - 轻量级锁还使用了自旋锁来避免线程用户态与内核态的频繁切换,大大地提高了系统性能;
- 但如果锁竞争太激烈了,那么同步锁将会升级为重量级锁。
减少锁竞争,是优化Synchronized同步锁的关键。我们应该尽量使Synchronized
同步锁处于轻量级锁或偏向锁,这样才能提高Synchronized
同步锁的性能。
- 通过减小锁粒度来降低锁竞争也是一种最常用的优化方法,
ConcurrentHashMap
就很很巧妙地使用了分段锁Segment来降低锁资源竞争。 - 另外我们还可以通过减少锁的持有时间来提高
Synchronized
同步锁在自旋时获取锁资源的成功率,避免Synchronized
同步锁升级为重量级锁。
Lock同步锁
Lock锁是基于Java
实现的锁,Lock
是一个接口类,常用的实现类有ReentrantLock
、ReentrantReadWriteLock(RRW)
,它们都是依赖AbstractQueuedSynchronizer(AQS)
类实现的。
从性能方面上来说,在并发量不高、竞争不激烈的情况下,Synchronized
同步锁由于具有分级锁的优势,性能上与Lock
锁差不多;但在高负载、高并发的情况下,Synchronized
同步锁由于竞争激烈会升级到重量级锁,性能则没有Lock锁稳定。
ReentrantLock
是一个独占锁,同一时间只允许一个线程访问,而RRW
允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。读写锁内部维护了两个锁,一个是用于读操作的ReadLock
,一个是用于写操作的WriteLock
。
乐观锁
乐观锁,顾名思义,就是说在操作共享资源时,它总是抱着乐观的态度进行,它认为自己可以成功地完成操作。但实际上,当多个线程同时操作一个共享资源时,只有一个线程会成功,那么失败的线程呢?它们不会像悲观锁一样在操作系统中挂起,而仅仅是返回,并且系统允许失败的线程重试,也允许自动放弃退出操作。
CAS是实现乐观锁的核心算法,它包含了3个参数:V(需要更新的变量)、E(预期值)和N(最新值)。
只有当需要更新的变量等于预期值时,需要更新的变量才会被设置为最新值,如果更新值和预期值不同,则说明已经有其它线程更新了需要更新的变量,此时当前线程不做操作,返回V的真实值。
在JDK中的concurrent包中,atomic路径下的类都是基于CAS实现的。AtomicInteger就是基于CAS实现的一个线程安全的整型类。AtomicInteger依赖于本地方法Unsafe类,Unsafe类中的操作方法会调用CPU底层指令实现原子操作。
在数据库表中的内容时,根据表记录的version进行的更新操作,也是一种乐观锁机制。
锁优化总结
- 在读大于写的场景下,读写锁RRW的性能最佳。
- 在写大于读的场景下,乐观锁的性能是最好的,剩下的读写锁RRW、ReentrantLock、Synchronized的性能则相差不多。
- 在读和写差不多的场景下,读写锁RRW以及乐观锁的性能要优于Synchronized和ReentrantLock。
上下文切换优化
一个线程被剥夺处理器的使用权而被暂停运行,就是“切出”;一个线程被选中占用处理器开始或者继续运行,就是“切入”。在这种切出切入的过程中,操作系统需要保存和恢复相应的进度信息,这个进度信息就是“上下文”了。 而切入、切出的过程,需要进行上下文切换。
切入、切出过程中的进度信息,它包括了寄存器的存储内容以及程序计数器存储的指令内容。
可以使用 Linux 内核提供的 vmstat 命令,来监视 Java 程序运行过程中系统的上下文切换频率( system.cs
)。
[localhost /]
$vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st7 0 0 1870684 0 4104652 0 0 471 7420 0 0 0 0 100 0 0
如果是监视某个应用的上下文切换,就可以使用 pidstat命令监控指定进程的 Context Switch 上下文切换。
pidstat -w -l -p <pid> 1 100
# 212351 为进程的pid
[admin@nui-sus033103101131.pre.na620 /]
$pidstat -w -l -p 212351 1 100
Linux 5.10.134-010.x86_64 (localhost.localdomain) 12/11/2024 _x86_64_ (4 CPU)03:47:43 PM UID PID cswch/s nvcswch/s Command
03:47:44 PM 2368 212351 0.00 0.00 java -server -Xms5g -Xmx8g -Djava.util.Arrays.useLegacyMergeSort=true -Dproject.name=test -DLog4jContextSelector=org.apache.logg
03:47:45 PM 2368 212351 0.00 0.00 java -server -Xms5g -Xmx8g -Djava.util.Arrays.useLegacyMergeSort=true -Dproject.name=test -DLog4jContextSelector=org.apache.logg
03:47:46 PM 2368 212351 0.00 0.00 java -server -Xms5g -Xmx8g -Djava.util.Arrays.useLegacyMergeSort=true -Dproject.name=test -DLog4jContextSelector=org.apache.logg
03:47:47 PM 2368 212351 0.00 0.00 java -server -Xms5g -Xmx8g -Djava.util.Arrays.useLegacyMergeSort=true -Dproject.name=test -DLog4jContextSelector=org.apache.logg
03:47:48 PM 2368 212351 0.00 0.00 java -server -Xms5g -Xmx8g -Djava.util.Arrays.useLegacyMergeSort=true -Dproject.name=test -DLog4jContextSelector=org.apache.logg
03:47:49 PM 2368 212351 0.00 0.00 java -server -Xms5g -Xmx8g -Djava.util.Arrays.useLegacyMergeSort=true -Dproject.name=test -DLog4jContextSelector=org.apache.logg
03:47:50 PM 2368 212351 0.00 0.00 java -server -Xms5g -Xmx8g -Djava.util.Arrays.useLegacyMergeSort=true -Dproject.name=test -DLog4jContextSelector=org.apache.logg
03:47:51 PM 2368 212351 0.00 0.00 java -server -Xms5g -Xmx8g -Djava.util.Arrays.useLegacyMergeSort=true -Dproject.name=test -DLog4jContextSelector=org.apache.logg
我们可以分两种情况来分析,一种是程序本身触发的切换,这种我们称为自发性上下文切换,另一种是由系统或者虚拟机诱发的非自发性上下文切换。
自发性上下文切换指线程由 Java 程序调用导致切出,在多线程编程中,执行调用以下方法或关键字,常常就会引发自发性上下文切换。
- sleep()
- wait()
- yield()
- join()
- park()
- synchronized
- lock
非自发性上下文切换指线程由于调度器的原因被迫切出。常见的有:线程被分配的时间片用完,虚拟机垃圾回收导致或者执行优先级的问题导致。
上下文切换是多线程编程性能消耗的原因之一,而竞争锁、线程间的通信以及过多地创建线程等多线程编程操作,都会给系统带来上下文切换。除此之外,I/O阻塞以及JVM的垃圾回收也会增加上下文切换。
所以多线程上下文切换优化包括以下几点建议:
-
竞争锁优化
- 减少锁持有时间
- 降低锁粒度。锁分离,比如读写锁RRW;锁分段,比如
ConcurrentHashMap
。 - 非阻塞乐观锁替代竞争锁
-
wait/notify优化
- 首先,可以使用
Object.notify()
替代Object.notifyAll()
。 因为Object.notify()
只会唤醒指定线程,不会过早地唤醒其它未满足需求的阻塞线程,所以可以减少相应的上下文切换。 - 使用Lock锁结合Condition 接口替代
Synchronized
内部锁中的wait / notify
,实现等待/通知。
- 首先,可以使用
-
合理地设置线程池大小,避免创建过多线程
-
使用协程实现非阻塞等待
-
减少Java虚拟机的垃圾回收
很多 JVM 垃圾回收器(serial收集器、ParNew收集器)在回收旧对象时,会产生内存碎片,从而需要进行内存整理,在这个过程中就需要移动存活的对象。而移动内存对象就意味着这些对象所在的内存地址会发生变化,因此在移动对象前需要暂停线程,在移动完成后需要再次唤醒该线程。因此减少 JVM 垃圾回收的频率可以有效地减少上下文切换。
并发容器的使用
并发场景下的Map容器
- 如果对数据有强一致要求,则需使用
Hashtable
; - 在大部分场景通常都是弱一致性的情况下,使用
ConcurrentHashMap
即可; - 如果数据量在千万级别,且存在大量增删改操作,则可以考虑使用
ConcurrentSkipListMap
。
并发场景下的List容器
- 如果对数据有强一致要求,则需使用
Vector
; CopyOnWriteArrayList
,适用于读远大于写的操作场景。
线程池参数
public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量int maximumPoolSize,//线程池的最大线程数long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间TimeUnit unit,//时间单位BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可RejectedExecutionHandler handler) //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
下图描述了线程池参数的关系
在创建完线程池之后,默认情况下,线程池中并没有任何线程,等到有任务来才创建线程去执行任务。但有一种情况排除在外,就是调用
prestartAllCoreThreads()
或者prestartCoreThread()
方法的话,可以提前创建等于核心线程数的线程数量,这种方式被称为预热。
- 当创建的线程数等于
corePoolSize
时,提交的任务会被加入到设置的阻塞队列中。当队列满了,会创建线程执行任务,直到线程池中的数量等于maximumPoolSize
。 - 当线程数量已经等于
maximumPoolSize
时, 新提交的任务无法加入到等待队列,也无法创建非核心线程直接执行,我们又没有为线程池设置拒绝策略,这时线程池就会抛出RejectedExecutionException
异常,即线程池拒绝接受这个任务。 - 当线程池中创建的线程数量超过设置的
corePoolSize
,在某些线程处理完任务后,如果等待keepAliveTime
时间后仍然没有新的任务分配给它,那么这个线程将会被回收。线程池回收线程时,会对所谓的“核心线程”和“非核心线程”一视同仁,直到线程池中线程的数量等于设置的corePoolSize
参数,回收过程才会停止。
即使是corePoolSize线程,在一些非核心业务的线程池中,如果长时间地占用线程数量,也可能会影响到核心业务的线程池,这个时候就需要把没有分配任务的线程回收掉。
- 通过
allowCoreThreadTimeOut
设置项要求线程池:将包括“核心线程”在内的,没有任务分配的所有线程,在等待keepAliveTime
时间后全部回收掉。
一般多线程执行的任务类型可以分为CPU密集型和I/O密集型,根据不同的任务类型,我们计算线程数的方法也不一样。
- CPU密集型任务:这种任务消耗的主要是CPU资源,可以将线程数设置为N(CPU核心数)+1,比CPU核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用CPU的空闲时间。
- I/O密集型任务:这种任务应用起来,系统会用大部分的时间来处理I/O交互,而线程在处理I/O的时间段内不会占用CPU来处理,这时就可以将CPU交出给其它线程使用。因此在I/O密集型任务的应用中,我们可以多配置一些线程,具体的计算方法是2N。
- 碰上一些常规的业务操作,比如,通过一个线程池实现向用户定时推送消息的业务,此时我们可以参考以下公式来计算线程数:
线程数=N(CPU核数)*(1+WT(线程等待时间)/ST(线程时间运行时间))
综合来看,我们可以根据自己的业务场景,从“N+1”和“2N”两个公式中选出一个适合的,计算出一个大概的线程数量,之后通过实际压测,逐渐往“增大线程数量”和“减小线程数量”这两个方向调整,然后观察整体的处理时间变化,最终确定一个具体的线程数量。
线程池参数 - blockingQueue 多线程队列:在Java多线程应用中,特别是在线程池中,队列的使用率非常高。Java提供的线程安全队列又分为了阻塞队列和非阻塞队列。
阻塞队列
- ArrayBlockingQueue:一个基于数组结构实现的有界阻塞队列,按 FIFO(先进先出)原则对元素进行排序,使用ReentrantLock、Condition来实现线程安全;
- LinkedBlockingQueue:一个基于链表结构实现的阻塞队列,同样按FIFO (先进先出) 原则对元素进行排序,使用ReentrantLock、Condition来实现线程安全,吞吐量通常要高于ArrayBlockingQueue;
- PriorityBlockingQueue:一个具有优先级的无限阻塞队列,基于二叉堆结构实现的无界限(最大值Integer.MAX_VALUE - 8)阻塞队列,队列没有实现排序,但每当有数据变更时,都会将最小或最大的数据放在堆最上面的节点上,该队列也是使用了ReentrantLock、Condition实现的线程安全;
- DelayQueue:一个支持延时获取元素的无界阻塞队列,基于PriorityBlockingQueue扩展实现,与其不同的是实现了Delay延时接口;
- SynchronousQueue:一个不存储多个元素的阻塞队列,每次进行放入数据时, 必须等待相应的消费者取走数据后,才可以再次放入数据,该队列使用了两种模式来管理元素,一种是使用先进先出的队列,一种是使用后进先出的栈,使用哪种模式可以通过构造函数来指定。
非阻塞队列
- ConcurrentLinkedQueue,它是一种无界线程安全队列(FIFO),基于链表结构实现,利用CAS乐观锁来保证线程安全。
使用协程来优化多线程业务
线程实现模型
-
1:1线程模型:Linux操作系统编程中,往往都是通过fork()函数创建一个子进程来代表一个内核中的线程,这会产生大量冗余数据,即占用大量内存空间,又消耗大量CPU时间用来初始化内存空间以及复制数据。
这时候轻量级进程(Light Weight Process,即LWP)出现了。相对于fork()系统调用创建的线程来说,LWP使用clone()系统调用创建线程,该函数是将部分父进程的资源的数据结构进行复制,复制内容可选,且没有被复制的资源可以通过指针共享给子进程。因此,轻量级进程的运行单元更小,运行速度更快。LWP是跟内核线程一对一映射的,每个LWP都是由一个内核线程支持。
-
N:1线程模型:1:1线程模型在线程创建、切换上都存在用户态和内核态的切换,性能开销比较大。除此之外,它还存在局限性,主要就是指系统的资源有限,不能支持创建大量的LWP。
N:1线程模型是在用户空间完成了线程的创建、同步、销毁和调度,已经不需要内核的帮助了,也就是说在线程创建、同步、销毁的过程中不会产生用户态和内核态的空间切换,因此线程的操作非常快速且低消耗
-
N:M线程模型:N:1线程模型的缺点在于操作系统不能感知用户态的线程,因此容易造成某一个线程进行系统调用内核线程时被阻塞,从而导致整个进程被阻塞。
N:M线程模型是基于上述两种线程模型实现的一种混合线程管理模型,即支持用户态线程通过LWP与内核线程连接,用户态的线程数量和内核态的LWP数量是N:M的映射关系。
- JDK 1.8 Thread.java 中 Thread#start 方法的实现,实际上是通过Native调用start0方法实现的;在Linux下, JVM Thread的实现是基于pthread_create实现的,而pthread_create实际上是调用了clone()完成系统调用创建线程的。所以,目前Java在Linux操作系统下采用的是用户线程加轻量级线程,一个用户线程映射到一个内核线程,即1:1线程模型。
- Go语言是使用了N:M线程模型实现了自己的调度器,它在N个内核线程上多路复用(或调度)M个协程,协程的上下文切换是在用户态由协程调度器完成的,因此不需要陷入内核,相比之下,这个代价就很小了。
目前Kilim协程框架在Java中应用得比较多,通过这个框架,开发人员就可以低成本地在Java中使用协程了。
感兴趣的可以通过Kilim官方资料学写下。
在有严重阻塞的场景下,协程的性能更胜一筹。其实,I/O阻塞型场景也就是协程在Java中的主要应用。但话说回来,协程还是在Go语言中的应用较为成熟,在Java中的协程目前还不是很稳定,重点是缺乏大型项目的验证,可以说Java的协程设计还有很长的路要走。
什么是数据的强、弱一致性?
严格一致性(强一致性):所有的读写操作都按照全局时钟下的顺序执行,且任何时刻线程读取到的缓存数据都是一样的,Hashtable就是严格一致性;
顺序一致性:多个线程的整体执行可能是无序的,但对于单个线程而言执行是有序的,要保证任何一次读都能读到最近一次写入的数据,volatile可以阻止指令重排序,所以修饰的变量的程序属于顺序一致性;
弱一致性:不能保证任何一次读都能读到最近一次写入的数据,但能保证最终可以读到写入的数据,单个写锁+无锁读,就是弱一致性的一种实现。
相关文章:

Java性能调优 - 多线程性能调优
锁优化 Synchronized 在JDK1.6中引入了分级锁机制来优化Synchronized。当一个线程获取锁时 首先对象锁将成为一个偏向锁,这样做是为了优化同一线程重复获取锁,导致的用户态与内核态的切换问题;其次如果有多个线程竞争锁资源,锁…...
行为树详解(4)——节点参数配置化
【分析】 行为树是否足够灵活强大依赖于足够丰富的各类条件节点和动作节点,在实现这些节点时,不可避免的,节点本身需要有一些参数供配置。 这些参数可以分为静态的固定值的参数以及动态读取设置的参数。 静态参数直接设置为Public即可&…...
计算机网络中的三大交换技术详解与实现
目录 计算机网络中的三大交换技术详解与实现1. 计算机网络中的交换技术概述1.1 交换技术的意义1.2 三大交换技术简介 2. 电路交换技术2.1 理论介绍2.2 Python实现及代码详解2.3 案例分析 3. 分组交换技术3.1 理论介绍3.2 Python实现及代码详解3.3 案例分析 4. 报文交换技术4.1 …...
《杨辉三角》
题目描述 给出 n(1≤n≤20)n(1≤n≤20),输出杨辉三角的前 nn 行。 如果你不知道什么是杨辉三角,可以观察样例找找规律。 输入格式 无 输出格式 无 输入输出样例 输入 #1复制 6 输出 #1复制 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 C语言…...

ARM学习(35)单元测试框架以及MinGW GCC覆盖率报告
单元测试框架以及MinGW GCC覆盖率报告 1、单元测试与覆盖率简介 随着代码越写越多,越来越需要注意自测的重要性,基本可以提前解决90%的问题,所以就来介绍一下单元测试,单元测试是否测试充分,需要进行评价,覆盖率就是单元测试是否充分的评估工具。 例如跑过单元测试后,…...

边缘计算+人工智能:让设备更聪明的秘密
引言:日常生活中的“智能”设备 你是否发现,身边的设备正变得越来越“聪明”? 早上醒来时,智能音箱已经根据你的日程播放舒缓音乐;走进厨房,智能冰箱提醒你今天的食材库存;而在城市道路上&…...
neo4j知识图谱AOPC的安装方法
AOPC下载链接:aopc全版本github下载 APOC,全称为Awesome Procedures On Cypher,是Neo4j图数据库的一个非常强大和流行的扩展库。它极大地丰富了Cypher查询语言的功能,提供了超过450个过程(procedures)和函数…...

图像分割数据集植物图像叶片健康状态分割数据集labelme格式180张3类别
数据集格式:labelme格式(不包含mask文件,仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数):180 标注数量(json文件个数):180 标注类别数:3 标注类别名称:["Healthy","nitrogen deficiency"…...

Python学习(二)—— 基础语法(上)
目录 一,表达式和常量和变量 1.1 表达式 1.2 变量 1.3 动态类型特性 1.4 输入 二,运算符 2.1 算术运算符 2.2 关系运算符 2.3 逻辑运算符 2.4 赋值运算符 2.5 练习 三,语句 3.1 条件语句 3.2 while循环 3.3 for循环 四&#…...

Cesium-(Primitive)-(CircleOutlineGeometry)
CircleOutlineGeometry 效果: CircleOutlineGeometry 是 CesiumJS 中的一个类,它用来描述在椭球体上圆的轮廓。以下是 CircleOutlineGeometry 的构造函数属性,以表格形式展示: 属性名类型默认值描述centerCartesian3圆心点在固定坐标系中的坐标。radiusnumber圆的半径,…...
计算机网络技术基础:2.计算机网络的组成
计算机网络从逻辑上可以分为两个子网:资源子网和通信子网。 一、资源子网 资源子网主要负责全网的数据处理业务,为全网用户提供各种网络资源与网络服务。资源子网由主机、终端、各种软件资源与信息资源等组成。 1)主机 主机是资源子网的主要…...
EasyExcel使用管道流连接InputStream和OutputStream
前言 Java中的InputSteam 是程序从其中读取数据, OutputSteam是程序可以往里面写入数据。 如果我们有在项目中读取数据库的记录, 在转存成Excel文件, 再把文件转存到OSS中。 生成Excel使用的是阿里的EasyExcel 。 他支持Output的方式写出文件内容。 而…...
OpenWebUI连接不上Ollama模型,Ubuntu24.04
这里写自定义目录标题 问题介绍解决方法 问题介绍 操作系统 Ubuntu24.04Ollama 使用默认安装方法(官网https://github.com/ollama/ollama) curl -fsSL https://ollama.com/install.sh | sh 安装在本机OpenWebUI 使用默认docker安装方法(官网…...
C#C++获取当前应用程序的安装目录和工作目录
很多时候,用户自己点击打开read.exe加载的时候都没有问题,读取ini配置文件也没有问题。但是如果应用程序是开机启动呢?32位Windows系统当前目录是C盘的windows\system32;而64位系统软件启动后默认的当前目录是:C:\Wind…...

Linux中vi和vim的区别详解
文章目录 Linux中vi和vim的区别详解一、引言二、vi和vim的起源与发展三、功能和特性1、语法高亮2、显示行号3、编辑模式4、可视化界面5、功能扩展6、插件支持 四、使用示例1、启动编辑器2、基本操作 五、总结 Linux中vi和vim的区别详解 一、引言 在Linux系统中,vi和…...

2021 年 6 月青少年软编等考 C 语言四级真题解析
目录 T1. 数字三角形问题思路分析T2. 大盗思路分析T3. 最大子矩阵思路分析T4. 小球放盒子思路分析T1. 数字三角形问题 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。 注…...

UE5编辑器下将RenderTarget输出为UTexture并保存
在使用UE5开发项目时,RenderTarget是一种非常强大的工具,常用于生成实时纹理效果、后处理和调试。而将RenderTarget的内容转换为UTexture并储存,是许多编辑器内的需求都需要的功能。 1.材质球输出至Texture 首先创建一个Actor类,…...

【漏洞复现】CVE-2024-34102 Magento Open Source XXE漏洞
目录 漏洞介绍 影响版本 环境搭建 查看版本 漏洞复现 手动复现 漏洞 poc Magento Open Source 是一个免费开源的电子商务平台,适合中小企业或开发团队通过自定义代码和插件创建在线商店。它由社区开发和支持,功能强大但需要更多的技术投入。Adobe…...
soul大数据面试题及参考答案
如何看待数据仓库? 数据仓库是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策。 从数据存储角度看,它整合了来自多个数据源的数据。这些数据源可能包括业务系统数据库、日志文件等各种结构化和非结构化数据。例如,在电商企业中,它会整合订…...

GLM-4-Plus初体验
引言:为什么高效的内容创作如此重要? 在当前竞争激烈的市场环境中,内容创作已成为品牌成功的重要支柱。无论是撰写营销文案、博客文章、社交媒体帖子,还是制作广告,优质的内容不仅能够帮助品牌吸引目标受众的注意力&a…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...