原子类、AtomicLong、AtomicReference、AtomicIntegerFieldUpdater、LongAdder
原子类
JDK提供的原子类,即Atomic*
类有很多,大体可做如下分类:
形式 | 类别 | 举例 |
---|---|---|
Atomic* | 基本类型原子类 | AtomicInteger、AtomicLong、AtomicBoolean |
Atomic*Array | 数组类型原子类 | AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray |
Atomic*Reference | 引用类型原子类 | AtomicReference、AtomicStampedReference、AtomicMarkableReference |
Atomic*FieldUpdater | 升级类型原子类 | AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater |
*Adder | 自增器 | LongAdder、DoubleAdder |
*Accumulator | 累加器 | LongAccumulator、DoubleAccumulator |
引入原因
JDK为何要引入如此多的原子类API。
因为Java中的运算操作,如自增(++)或自减(–)都不是原子性操作,若没有进行额外的同步操作,在多线程环境下就是线程不安全。给变量增加volatile关键词也不管用。
volatile的作用是:
- 可见性:对volatile变量所有的写操作都能立即反应到其他线程中;
- 有序性:禁止指令的重排序优化。
并不能保证自增或自减操作的原子性。
AtomicLong
JDK1.5引入的AtomicLong,作用是对长整形对象进行原子操作。类似地,AtomicInteger用于对整形对象进行原子操作;AtomicBoolean用于对Boolean对象进行原子操作。这几个API的方法非常相似。
示例
直接给出代码:
public class AtomicLongExample {private static final AtomicLong counter = new AtomicLong();public static void increment() {counter.incrementAndGet();}public static long get() {return counter.get();}
}
可知:实现起来非常简单。
原理
看看AtomicLong.incrementAndGet()
源码:
public class AtomicLong extends Number implements Serializable {private static final Unsafe U = Unsafe.getUnsafe();private static final long VALUE = U.objectFieldOffset(AtomicLong.class, "value");public final long incrementAndGet() {return U.getAndAddLong(this, VALUE, 1L) + 1L;}
}
继续看Unsafe类的getAndAddLong方法:
@IntrinsicCandidate
public final long getAndAddLong(Object o, long offset, long delta) {long v;do {v = getLongVolatile(o, offset);} while (!weakCompareAndSetLong(o, offset, v, v + delta));return v;
}@IntrinsicCandidate
public native long getLongVolatile(Object o, long offset);// weakCompareAndSetLong方法最后调用
@IntrinsicCandidate
public final native boolean compareAndSetLong(Object o, long offset, long expected, long x);
最后是调用native方法。通过Unsafe的CAS指令实现线程安全地、原子性自增操作。
问题
这里提前给出结论,这也是JDK1.8引入LongAdder类的原因:
在多线程竞争不激烈的情况下,这样做是合适的。但是如果线程竞争激烈,会造成大量线程在原地打转、不停尝试去修改值,但再次发现值已被修改,于是继续自旋。浪费大量的CPU资源。
AtomicLong持有的成员变量value是volatile关键字修饰的,线程修改临界资源后,需要刷新到其他线程,也是要费一番功夫的。
严重情况下,volatile可能导致总线风暴问题。
AtomicReference
AtomicReference是JDK1.5开始提供的一种用于原子操作对象引用的类,位于java.util.concurrent.atomic
包。提供一种非阻塞的线程安全方式来更新和读取对象引用,使用的是底层的原子操作来保证操作的原子性。
适用场景
- 非阻塞算法:在多线程环境下需要实现高效、低延迟的非阻塞算法时,AtomicReference是一个很好的选择。它通过CAS操作避免传统锁机制的开销,适用于对性能要求高的场景;
- 引用类型的原子更新:当需要对引用类型(如对象)的更新操作保持原子性时,可使用AtomicReference。例如,在单例模式中,通过CAS操作来确保单例实例的唯一性;
- 构建高效的并发数据结构:可以用于构建各种并发数据结构,如无锁队列、无锁栈、无锁链表等;
- 实现不可变对象的原子替换:对于不可变对象,可使用AtomicReference实现原子替换操作,保证在多线程环境下的安全性。例如,引用类型的配置更新,确保配置更新的原子性和可见性。
实例
使用AtomicReference实现简单CAS操作:
@Slf4j
public class AtomicReferenceExample {public static void main(String[] args) {AtomicReference<String> atomicString = new AtomicReference<>("initialValue");log.info("Current value: " + atomicString.get());// 使用compareAndSet原子更新值boolean success = atomicString.compareAndSet("initialValue", "newValue");log.info("Updated value: " + atomicString.get());// 直接设置新值atomicString.set("anotherValue");log.info("Directly set value: " + atomicString.get());}
}
可知:和AtomicLong非常相似。
原理
- CAS操作(Compare-And-Set):基于硬件支持的CAS原子操作实现。这种操作包括三个步骤:比较当前值是否等于预期值,如果相等则将其更新为新值,如果不相等则不进行任何操作。CAS是一种无锁(lock-free)算法,可避免传统锁机制带来的性能问题和死锁风险。
- 内存可见性:使用volatile关键字确保引用变量的可见性。所有对AtomicReference的写操作都会立即对所有线程可见,读取操作也总是能获取最新的值。
AtomicReference提供的一系列方法:
get()
:获取当前的引用值;set(V newValue)
:设置当前引用值为新值;lazySet(V newValue)
:惰性设置为新值;compareAndSet(V expect, V update)
:如果当前引用值等于预期值,则将其更新为新值;getAndSet(V newValue)
:获取当前引用值并设置为新值;weakCompareAndSet(V expect, V update)
:类似于compareAndSet
,但在一些平台上可能有更高的性能;weakCompareAndSetPlain(V expectedValue, V newValue)
:getAndUpdate(UnaryOperator<V> updateFunc)
:updateAndGet(UnaryOperator<V> updateFunc)
:getAndAccumulate(V x, BinaryOperator<V> accumulatorFunc)
:accumulateAndGet(V x, BinaryOperator<V> accumulatorFunc)
:
JDK9又新增一系列方法:
- getPlain
- setPlain
- getOpaque
- setOpaque
- getAcquire
- setRelease
- compareAndExchange
- compareAndExchangeAcquire
- compareAndExchangeRelease
- weakCompareAndSetVolatile
- weakCompareAndSetAcquire
- weakCompareAndSetRelease
总结
AtomicReference是一种高效、线程安全的工具,用于在并发环境中进行原子引用操作。它依赖于CAS操作来实现无锁的原子性更新,适用于构建高性能的并发数据结构和非阻塞算法。在实际应用中,可根据具体需求选择使用AtomicReference来替代传统的锁机制,以提高并发程序的性能和可靠性。
AtomicIntegerFieldUpdater
AtomicXXXFieldUpdater是JDK提供的一种用于更新对象中某些字段值的工具,提供一种低开销、高性能的方式来对对象的字段进行原子操作。适合某些特定场景,尤其是在需要对对象的整型字段实现线程安全更新时。包括:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater和AtomicReferenceFieldUpdater。下面以AtomicIntegerFieldUpdater为例讲解。
适用场景:
- 高性能计数器或标志位更新:需要频繁更新对象中的某个计数器或标志字段,但又不想将整个对象进行锁定;
- 基于 POJO 对象的非静态字段更新:如果字段不能声明为 AtomicInteger(如 POJO 中的普通整型字段),AtomicIntegerFieldUpdater 提供了原子化更新的方法;
- 内存优化场景:相比直接使用AtomicInteger,通过AtomicIntegerFieldUpdater不需要为每个整型字段额外创建一个AtomicInteger对象;
- 避免锁开销:替代传统的synchronized或ReentrantLock,减少线程间竞争和锁的性能开销。适合高并发环境下的小粒度操作;
- 共享对象字段的线程安全管理:在缓存、计数器池等场景中,共享对象的某个字段需要被多个线程安全地读写。
AtomicIntegerFieldUpdater的核心优势在于提供对对象字段的原子操作,节省内存,减少锁开销。适用于高性能的计数或标志更新场景,但由于功能较为有限,更多的复杂线程同步需求可能需要其他工具(如Lock或ConcurrentHashMap)。
示例
假设需要对某个对象的int字段count进行线程安全的递增操作:
public class Example {// 字段必须是volatile、非静态、int基础类型private volatile int count;// 创建 AtomicIntegerFieldUpdaterprivate static final AtomicIntegerFieldUpdater<Example> updater = AtomicIntegerFieldUpdater.newUpdater(Example.class, "count");public int increment() {return updater.incrementAndGet(this); // 原子递增}public int get() {return updater.get(this); // 获取值}public static void main(String[] args) {Example example = new Example();log.info(example.increment()); // 输出:1}
}
原理
AtomicIntegerFieldUpdater是一个抽象泛型类,构造函数是protected,不能直接构造其对象,必须通过它提供的一个静态方法来创建:
// 受保护的不执行任何操作的构造函数,供子类使用
protected AtomicIntegerFieldUpdater() {
}@CallerSensitive
public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());
}
newUpdater()
静态方法传入的是要修改的类和对应的成员变量的名字,内部通过反射拿到这个类的成员变量,然后包装成一个AtomicIntegerFieldUpdater对象(即AtomicIntegerFieldUpdaterImpl)。所以,这个对象表示的是类的某个成员,而不是对象的成员变量。
然后可使用其一系列方法:
- compareAndSet
- weakCompareAndSet
- set
- lazySet
- get
- getAndSet
- getAndIncrement
- getAndDecrement
- getAndAdd
- incrementAndGet
- decrementAndGet
- addAndGet
- getAndUpdate
- updateAndGet
- getAndAccumulate
- accumulateAndGet
以getAndAdd方法为例,其源码如下:
public int getAndAdd(T obj, int delta) {int prev, next;do {prev = get(obj);next = prev + delta;} while (!compareAndSet(obj, prev, next));return prev;
}
get方法如下:
public final int get(T obj) {accessCheck(obj);return U.getIntVolatile(obj, offset);
}
compareAndSet方法如下:
public final boolean compareAndSet(T obj, int expect, int update) {accessCheck(obj);return U.compareAndSetInt(obj, offset, expect, update);
}
accecssCheck方法检查该obj是不是cclass类型,如果不是,则拒绝修改并抛出异常。
U是Unsafe,使用其CAS方法,参考Unsafe入门讲解。
AtomicIntegerFieldUpdaterImpl是一个静态私有内部实现类Impl,其构造函数为:
AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName, final Class<?> caller) {final Field field;final int modifiers;try {field = AccessController.doPrivileged(new PrivilegedExceptionAction<Field>() {public Field run() throws NoSuchFieldException {return tclass.getDeclaredField(fieldName);}});modifiers = field.getModifiers();sun.reflect.misc.ReflectUtil.ensureMemberAccess(caller, tclass, null, modifiers);ClassLoader cl = tclass.getClassLoader();ClassLoader ccl = caller.getClassLoader();if ((ccl != null) && (ccl != cl) && ((cl == null) || !isAncestor(cl, ccl))) {sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);}} catch (PrivilegedActionException pae) {throw new RuntimeException(pae.getException());} catch (Exception ex) {throw new RuntimeException(ex);}if (field.getType() != int.class)throw new IllegalArgumentException("Must be integer type");if (!Modifier.isVolatile(modifiers))throw new IllegalArgumentException("Must be volatile type");// 受保护字段成员的访问仅限于访问类或其子类之一的接收者,并且访问类又必须是受保护成员定义类的子类(或包兄弟)// 如果更新程序引用当前包之外的声明类的受保护字段,则接收者参数将缩小到访问类的类型this.cclass = (Modifier.isProtected(modifiers) && tclass.isAssignableFrom(caller) && !isSamePackage(tclass, caller)) ? caller : tclass;this.tclass = tclass;this.offset = U.objectFieldOffset(field);
}
可知:要想使用AtomicIntegerFieldUpdater修改成员变量,成员变量必须是volatile的int类型(不能是包装类)。
对比
工具 | 特点 | 适用场景 |
---|---|---|
AtomicIntegerFieldUpdater | 低内存开销,对对象的字段进行原子更新 | 对对象的单一字段进行高性能原子操作 |
AtomicInteger | 独立对象的原子更新,使用简单,但需要额外的内存空间 | 独立计数器或标志位 |
synchronized/Lock | 适合复杂的临界区保护 | 复杂的线程同步逻辑 |
LongAdder | 提供高并发场景下的高效累加器,减少线程争用 | 高并发场景的全局计数器 |
LongAdder
JDK1.8中新加入一个原子类LongAdder,该类可保证Long类型操作的原子性。相对于AtomicLong,LongAdder有着更高的性能(减少乐观锁的重试次数)和更好的表现,可完全替代AtomicLong来进行原子操作。
当大量线程同时访问AtomicLong时,会因为大量线程执行CAS操作失败而进行空旋转,导致CPU资源消耗过多,执行效率不高。
示例
直接给出代码:
public class LongAdderExample {private static final LongAdder counter = new LongAdder();public static void increment() {counter.increment();}public static long get() {return counter.sum();}
}
可见:实现起来非常简单。
原理
基于CAS分段锁的思想实现的。线程去读写一个LongAdder类型的变量时的流程:
LongAdder基于Unsafe提供的CAS操作+valitale去实现的。在LongAdder的父类Striped64中维护着base变量和cells数组,当多个线程操作一个变量时,先会在这个base变量上进行CAS操作,当它发现线程增多时,就会使用cells数组。比如当base将要更新时发现线程增多(调用casBase方法更新base值失败),则会自动使用cells数组,每一个线程对应于一个cell,在每一个线程中对该cells进行CAS操作,这样就可以将单一value的更新压力分担到多个value中去,降低单个value的热度,同时也减少大量线程的空转,提高并发效率,分散并发压力。这种分段锁需要额外维护一个内存空间cells,在高并发场景下,这点成本几乎可忽略。
利用空间来换时间,将热点value分散成一个Cell列表来承接并发的CAS,以此来提升性能。
Benchmark
一个简单不太严谨的Benchmark性能测试:
@Slf4j
public class AtomicLongTester {private static AtomicLong numA = new AtomicLong(0);private static LongAdder numB = new LongAdder();public static void main(String[] args) throws InterruptedException {for (int i = 1; i < 10001; i*=10) {test(false, i);test(true, i);}}public static void test(boolean isLongAdder, int threadCount) throws InterruptedException {long starTime = System.currentTimeMillis();final CountDownLatch latch = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {new Thread(new Runnable() {public void run() {for (int i = 0; i < 100000; i++) {if (isLongAdder) {numB.add(1);} else {numA.addAndGet(1);}}latch.countDown();}}).start();}// 等待所有运算结束 latch.await();if (isLongAdder) {log.info("Thread Count=" + threadCount + ", LongAdder cost ms=" + (System.currentTimeMillis() - starTime) + ", Result=" + numB.sum());} else {log.info("Thread Count=" + threadCount + ", AtomicLong cost ms=" + (System.currentTimeMillis() - starTime) + ", Result=" + numA.get());}numA = new AtomicLong(0);numB = new LongAdder();}
}
某次运行结果:
Thread Count=1, AtomicLong cost ms=9, Result=100000
Thread Count=1, LongAdder cost ms=13, Result=100000
Thread Count=10, AtomicLong cost ms=14, Result=1000000
Thread Count=10, LongAdder cost ms=41, Result=1000000
Thread Count=100, AtomicLong cost ms=111, Result=10000000
Thread Count=100, LongAdder cost ms=45, Result=10000000
Thread Count=1000, AtomicLong cost ms=1456, Result=100000000
Thread Count=1000, LongAdder cost ms=379, Result=100000000
Thread Count=10000, AtomicLong cost ms=17452, Result=1000000000
Thread Count=10000, LongAdder cost ms=3545, Result=1000000000
可见:当线程竞争率比较低时,AtomicLong效率优于LongAdder的,但当线程竞争率增大时,可看出LongAdder的性能远远高于AtomicLong。
对比
对比项 | AtomicLong | LongAdder |
---|---|---|
原理 | Unsafe类CAS指令 | 分段累加;使用内部的多个Cell(类似于分段桶),每个线程可独立更新不同Cell,减少竞争 |
空间开销 | 只需一个long变量,内存占用小 | 内部包含多个Cell,每个Cell是一个独立变量,占用更多内存 |
低并发 | 更新只需要操作单一变量,执行路径更短;性能较优且实现简单 | 需初始化多个Cell,即使只有一个线程使用,也需要额外的内存和初始化开销 |
高并发 | 多线程更新同一变量时,频繁CAS重试会导致性能瓶颈 | 减少线程争用,吞吐量更高 |
精度要求高 | 更适合 | 当需要获取总值时,会将所有Cell的值汇总;短时间内的结果可能不完全一致 |
LongAccumulator
有待学习。
参考
相关文章:
原子类、AtomicLong、AtomicReference、AtomicIntegerFieldUpdater、LongAdder
原子类 JDK提供的原子类,即Atomic*类有很多,大体可做如下分类: 形式类别举例Atomic*基本类型原子类AtomicInteger、AtomicLong、AtomicBooleanAtomic*Array数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArrayAtomic…...
MySQL(8)【聚合函数 | group by分组查询】
阅读导航 引言一、聚合函数1. 简介2. 使用示例(1)COUNT() 函数(2)SUM() 函数(3)AVG() 函数(4)MAX() 函数(5)MIN() 函数 二、group by分组查询1. 基本语法2. 按…...
如何监控Elasticsearch集群状态?
大家好,我是锋哥。今天分享关于【如何监控Elasticsearch集群状态?】面试题。希望对大家有帮助; 如何监控Elasticsearch集群状态? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 监控 Elasticsearch 集群的状态对于确保…...
React第七节 组件三大属性之 refs 的用法注意事项
1、定义 React 中refs 是允许我们操作DOM 访问组件实例的一种方案。开发人员可以直接使用 refs 访问操作DOM,而不用自身的数据状态,这种方案在实际开发过程中是有必要的,但是不建议通篇使用refs操作DOM,如果是这样,那…...
全文单词统计
目标:统计词频 import scala.io.Source //知识点 //1.字符串.split("分隔符"):把字符串用指定的分隔符。拆分成多份,保存在数组中 object test1 {def main(args: Array[String]): Unit { //从文件1.txt中读入内容val contentSourc…...
Angular v19 (二):响应式当红实现signal的详细介绍:它擅长做什么、不能做什么?以及与vue、svelte、react等框架的响应式实现对比
本文紧接着Angular v19 新版本来啦,一起瞧瞧新特性吧!,主要针对它在v18引入了一项全新的响应式技术——Signal,这引起了开发者社区的广泛关注,最新的v19版本推出了更多的signal工具。Signal的加入旨在优化Angular的响应…...
【数据结构】二叉搜索树(二叉排序树)
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:数据结构 目录 前言 一、什么是二叉搜索树 二、二叉搜索树的实现 节点 属性和接口的声明 插入 查找 删除 拷贝构造 析构 中序遍历 三、二叉搜索树的…...
文件的摘要算法(md5、sm3、sha256、crc)
为了校验文件在传输中保证完整性和准确性,因此需要发送方先对源文件产生一个校验码,并将该值传输给接收方,将附件通过ftph或http方式传输后,由接收方使用相同的算法对接收文件再获取一个新的校验码,将该值和发送方传的…...
Python实现人生重开模拟器
目录 人生重开模拟器介绍 代码实现 打印初始界面 设置初始属性 设置角色性别 设置角色出生点 针对每一岁,生成人生经历 完整代码 人生重开模拟器介绍 人生重开模拟器 是之前比较火的一个小游戏,我们这里使用 Python 实现一个简化版的 人生重开模…...
机器学习(二十五):决策树算法以及决策树和神经网络的对比
一、决策树集合 单一决策树会对训练数据的变化很敏感。例子:输入十个数据,判断是否是猫。只替换其中一个数据,信息增益最高的分裂特征就发生了改变,决策树就发生了变化。 使用决策树集合可以使算法更加健壮。例子:使用…...
k8s运行运行pod报错超出文件描述符表限制
1.问题描述 运行pod超过文件描述符表 unable to allocate file descriptor table - out of memory/opt/COMMAND.sh: line 9: 2.查看设备的文件描述符限制 操作前一定要先查询这个值,2097152这个值即为我们可设置的最大值,超过这个值后将无法登录&am…...
非常简单实用的前后端分离项目-仓库管理系统(Springboot+Vue)part 2
七、创建前端项目 你下载了nodejs吗?从cn官网下载:http://nodejs.cn/download/,或者从一个国外org网站下载,选择自己想要的版本https://nodejs.org/download/release/,双击下载好的安装文件,选择安装路径安…...
开源 AI 智能名片 2 + 1 链动模式 S2B2C 商城小程序源码助力品牌共建:价值、策略与实践
摘要:在当今数字化商业环境下,品牌构建已演变为企业与消费者深度共建的过程。本文聚焦于“开源 AI 智能名片 2 1 链动模式 S2B2C 商城小程序源码”,探讨其如何融入品牌建设,通过剖析品牌价值构成,阐述该技术工具在助力…...
微信小程序中的WXSS与CSS的关系及使用技巧
微信小程序中的WXSS与CSS的关系及使用技巧 引言 在微信小程序的开发中,样式的设计与实现是构建用户友好界面的关键。微信小程序使用WXSS(WeiXin Style Sheets)作为其样式表语言,WXSS在语法上与CSS非常相似,但也有一些独特的特性。本文将深入探讨WXSS与CSS的关系,介绍WX…...
STM32的CAN波特率计算
公式: CAN波特率 APB总线频率 / (BRP分频器 1)/ (SWJ BS1 BS2) SWJ一般为1。 例如STM32F407的,CAN1和CAN2都在在APB1下,频率是42000000 如果想配置成1M波特率,则计算公式为:...
【LeetCode面试150】——57插入区间
博客昵称:沈小农学编程 作者简介:一名在读硕士,定期更新相关算法面试题,欢迎关注小弟! PS:哈喽!各位CSDN的uu们,我是你的小弟沈小农,希望我的文章能帮助到你。欢迎大家在…...
活着就好20241128
早晨问候: 亲爱的朋友们,大家早上好!今天是2024年11月28日,第48周的第四天,也是十一月的第二十八天,农历甲辰[龙]年十月廿四。在这个即将步入月末、阳光依旧明媚的清晨,愿第一缕阳光轻轻洒落在…...
【kafka03】消息队列与微服务之Kafka 读写数据
Kafka 读写数据 参考文档 Apache Kafka 常见命令 kafka-topics.sh #消息的管理命令 kafka-console-producer.sh #生产者的模拟命令 kafka-console-consumer.sh #消费者的模拟命令 创建 Topic 创建topic名为 chen,partitions(分区)为3࿰…...
【Agorversev1.1数据转换】Agorverse高清地图转OpenStreetMap及SUMO路网
文章目录 Agorverse高清地图转OpenStreetMap及SUMO路网1. Agorverse osm转换说明2. 转换源码3. 处理效果4. SUMO-Carla联合仿真 Agorverse高清地图转OpenStreetMap及SUMO路网 1. Agorverse osm转换说明 根据作者的描述,其高清地图的osm文件与标准osm的区别在于以下…...
Vue 3 实现高性能拖拽指令的最佳实践
前言 在现代前端开发中,拖拽功能是增强用户体验的重要手段之一。本文将详细介绍如何在 Vue 3 中封装一个拖拽指令(v-draggable),并通过实战例子演示其实现过程。通过这篇教程,您将不仅掌握基础的拖拽功能,…...
AIGC--------AIGC在医疗健康领域的潜力
AIGC在医疗健康领域的潜力 引言 AIGC(Artificial Intelligence Generated Content,人工智能生成内容)是一种通过深度学习和自然语言处理(NLP)等技术生成内容的方式。近年来,AIGC在医疗健康领域展现出了极…...
Apache Calcite - calcite jdbc驱动使用场景
前言 在使用Calcite查询数据时通常会用到这些代码获取schema Connection connection DriverManager.getConnection("jdbc:calcite:", info); CalciteConnection calciteConnection connection.unwrap(CalciteConnection.class); SchemaPlus rootSchema calciteC…...
IEC61850实现方案和测试-4-MMS协议
IEC61850实现方案和测试-4作为介绍实现方案和测试的第四篇文章,后续会继续更新,欢迎关注。前三篇如下 第一篇是:IEC61850实现方案和测试-1-CSDN博客 第二篇是:IEC61850实现方案和测试-2-UCA-CSDN博客 第三篇是:IEC6…...
【ubuntu24.04】GTX4700 配置安装cuda
筛选显卡驱动显卡驱动 NVIDIA-Linux-x86_64-550.135.run 而后重启:最新的是12.6 用于ubuntu24.04 ,但是我的4700的显卡驱动要求12.4 cuda...
时间的礼物:如何珍视每一刻
《时间的礼物:如何珍视每一刻》 夫时间者,宇宙之精髓,生命之经纬,悄无声息而流转不息,如织锦之细线,串联古今,贯穿万物。 人生短暂,犹如白驹过隙,倏忽而逝,…...
componentReceivePropsreact class生命周期
componentReceiveProps并不是有props的变化触发,而是由父组件的更新触发的 父组件导致组件重新渲染,即使props没有更改,也会调用componentReceiveProps这个方法;如果只想处理更改,确保当前值与变更值比较--官方 …...
快速理解微服务中Sentinel怎么实现限流
Sentinel是通过动态管理限流规则,根据定义的规则对请求进行限流控制。 一.实现步骤 1.定义资源:在Sentinel中,资源可以是URL、方法等,用于标识需要进行限流的请求;(在Sentinel中,需要我们去告诉Sentinel哪些…...
25.100ASK_T113-PRO 测试摄像头(型号)
1.摄像头 USB2.0 摄像头,支持 UVC协议, 就是V4L2 USB2.0 大概可这样理解吧.这个是2K分辨率. 2.8mm焦距. 开发板还是 100ASK_T113-PRO V1.2版 2.查看摄像头驱动挂载情况 这样接好. 看看设备有没有挂载上 # ls /dev/video* /dev/video0 /dev/video1 这两个就是USB摄像头.说…...
20241127 给typecho文章编辑附件 添加视频 图片预览
Typecho在写文章时,如果一次性上传太多张图片可能分不清哪张,因为附件没有略缩图,无法实时阅览图片,给文章插入图片时很不方便。 编辑admin/file-upload.php 大约十八行的位置 一个while 循环里面,这是在进行html元素更新操作,在合…...
StarRocks-join优化
1、背景 有两个大表,都是6kw级别上下的,通过SR然后包装了一个接口对外提供查询,当前的问题是,这样大的join查询会导致BE直接宕机。并且这个sql很有代表性,我截图如下: 这个表是个单分区,所以直接…...
如何通过ChatGPT提高自己的编程水平
在编程学习的过程中,开发者往往会遇到各种各样的技术难题和学习瓶颈。传统的学习方法依赖书籍、教程、视频等,但随着技术的不断发展,AI助手的崛起为编程学习带来了全新的机遇。ChatGPT,作为一种强大的自然语言处理工具,…...
实时数据开发 | checkpoints监控和调优
监控Checkpoints 监控 checkpoint 行为最简单的方法是通过 UI 的 checkpoint 部分。 监控这两个指标: 算子收到第一个 checkpoint barrier 的时间。当触发 checkpoint 的耗费时间一直很高时,这意味着 checkpoint barrier 需要很长时间才能从 source 到达 operator…...
面试手撕题积累
1、实现滑动窗口限流,允许每分钟最多有100个请求 阿里一面题。 核心: 时间窗口管理:滑动窗口会根据时间流逝不断更新,需要记录请求的时间戳,并根据当前时间计算窗口内的请求数量。 限流判断:每次请求到来…...
开发中使用UML的流程_05 PIM-1:分析系统流程
目录 1、概述 2、PIM生成的过程 3、用例叙述格式 4、用例关系 5、执行流程: 6、惯用的编号方式 1、概述 在进入到PIM阶段之后,系统分析员将所有系统用例依相关性分成若干组,以组别方式生成该组系统用例涉及的PIM-1---PIM-4产生结果&am…...
【Go】-go中的锁机制
目录 一、锁的基础知识 1. 互斥量/互斥锁 2. CAS(compare and swap) 3. 自旋锁 4. 读写锁 5. 乐观锁 & 悲观锁 6. 死锁 二、go中锁机制 1. Mutex-互斥锁 2. RWMutex-读写锁 2.1 RWMutex流程概览 2.2 写锁饥饿问题 2.3. golang的读写锁源…...
Scala学习记录,全文单词统计
package test32 import java.io.PrintWriter import scala.io.Source //知识点 // 字符串.split("分隔符":把字符串用指定的分隔符,拆分成多个部分,保存在数组中) object test {def main(args: Array[String]): Unit {//从文件1.t…...
重构项目架构
前言 我们上篇文章对整个项目进行一个整体的规划,其中对于APP类规划了类,本篇文章我们就来实现这个规划; class App {//加载页面constructor() {}//获取位置_getPosition() {}//接受位置_loadMap() {}//在地图上点击展现表单_showForm() {}/…...
一个开源轻量级的服务器资源监控平台,支持告警推送
大家好,今天给大家分享一款开源的轻量级服务器资源监控工具Beszel,提供历史数据记录、Docker容器统计信息监控以及多种警报功能,用于监控服务器资源。 项目介绍 Beszel由hub(中心服务器端应用,基于PocketBase构建&…...
介绍一下atof(arr);(c基础)
hi , I am 36 适合对象c语言初学者 atof(arr);是返回浮点数(double型),浮点数数是arr数组中字符中数字 格式 #include<stdio.h> atof(arr); 返回值arr数组中的数 未改变arr数组 #include<stdio.h> //atof(arr) 返 <stdlib> int…...
基于微信小程序的平价药房管理系统+LW参考示例
1.项目介绍 系统角色:管理员、医生、普通用户功能模块:用户管理、医生管理、药品分类管理、药品信息管理、在线问诊管理、生活常识管理、日常提醒管理、过期处理、订单管理等技术选型:SpringBoot,Vue,uniapp等测试环境…...
什么是 C++ 中的函数对象?它有什么特点?如何定义和使用函数对象?数对象与普通函数有什么区别?
在 C 中,函数对象(Function Object)也被称为仿函数(Functor),是一种可以像函数一样被调用的对象,是一个类的对象,该类重载了函数调用运算符operator()。 函数对象的特点: 与普通函数…...
JAVA篇05 —— 内部类(Local、Anonymous、Member、Static)
欢迎来到我的主页:【一只认真写代码的程序猿】 本篇文章收录于专栏【小小爪哇】 如果这篇文章对你有帮助,希望点赞收藏加关注啦~ 目录 1 内部类Inner Class 1.1 局部内部类 1.2 匿名内部类(※※) 1.3 匿名类最佳实践…...
vmware安装ubuntu22.04 复制黏贴 上网
1、ubuntu下载 [Download - 清华镜像站]: 点击 清华大学开源软件镜像站 - Ubuntu 22.04.4 下载 页面中的 ubuntu-22.04.4-desktop-amd64.iso清华大学开源软件镜像站 - Ubuntu 22.04.4 下载 2、安装向导 3、网络设置 sudo netplan try sudo netplan apply4、复制…...
Spring Bean初始化流程
首先: 加载Bean定义(Configuration) 然后对于每个Bean: 1、实例化Bean(应该是从Bean方法中获取,Bean方法里面包含new这个类型的代码)2、依赖注入(所依赖的Bean要经历相同的流程)、调用Setter…...
C 语言函数递归探秘:从基础概念到复杂问题求解的进阶之路
我的个人主页 我的专栏:C语言,希望能帮助到大家!!!点赞❤ 收藏❤ 目录 什么是函数递归递归的基本组成递归的工作原理递归的优缺点递归的经典案例 5.1 阶乘计算5.2 斐波那契数列5.3 汉诺塔问题5.4 二分查找 递归的高级…...
【Zookeeper】三,Zookeeper的安装与基本操作
文章目录 安装Zookeeper下载解压解压后的目录结构运行Zookeeper 基本操作 安装Zookeeper 下载 官网下载Zookeeper,会得到一个tar包,如:apache-zookeeper-3.8.4-bin.tar.gz 解压 tar -xvf apache-zookeeper-3.8.4-bin.tar.gz -C /usr/loca…...
STL算法之数值算法<stl_numeric.h>
这一节介绍的算法,统称为数值(numeric)算法。STL规定,欲使用它们,客户端必须包含头文件<numeric>.SGI将它们实现与<stl_numeric.h>文件中。 目录 运用实例 accumulate adjacent_difference inner_product partial_sum pow…...
Git 入门超简单指南
1. 什么是 Git? Git 是一个分布式版本控制系统,由 Linus Torvalds 于 2005 年创建。它的主要目的是帮助开发者有效地管理和跟踪项目的历史版本。通过使用 Git,你可以轻松地记录每一次代码的修改,回滚到以前的版本,以及…...
UE5 和 UE4 中常用的控制台命令总结
调用控制台 按下键盘上的 ~ 键可以调用控制台命令。 技巧 使用键盘的 ↑ 键可以查看之前输入过的指令。控制台指令并不需要打全名,输入空格后跟随指令的部分字符可以进行模糊搜索。按下 Ctrl Shift , 打开 GPUProfile 面板。 命令如下: 调试类 s…...
[护网杯 2018]easy_tornado
这里有一个hint点进去看看,他说md5(cookie_secretmd5(filename)),所以我们需要获得cookie_secret的value 根据题目tornado,它可能是tornado的SSTI 这里吧filehash改为NULL. 是tornado的SSTI 输入{{handler.settings}} (settings 属性是一个字典&am…...