Java CAS操作
通过前面的学习认识到了CPU缓存,Java内存模型,以及线程安全的原子、可见、顺序三大特性。本文则重点认识CAS操作,这是Java并发编程常见的一个操作,AbstractQueuedSynchronizer基于此操作提供了丰富的同步器和各种锁。
CAS(CompareAndSwap)操作
- 用于实现
多线程同步
的原子指令
,非阻塞算法,是由CPU硬件实现的(x86下cmpxchg指令;arm下LL/SC指令),无需用到内核的同步原语来实现
CAS通过调用JNI(java native interface)的代码来操作底层指令来实现。
- Unsafe: compareAndSwap
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
- jdk8u: unsafe.cpp
cmpxchg = compare and exchange
- jdk8u atomic_linux_x86.inline.hpp
is_MP = Multi Processor
多CPU情况下会加上Lock
(Lock是确保原子性的)
结论:cmpxchg = cas修改变量值, lock cmpxchg 指令;硬件层面:lcok指令在执行后面指令的时候会锁定一个北桥芯片(确保只有一个CPU访问内存)
- 乐观锁(无锁的乐观机制)
CAS 的缺点
- ABA问题。因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A
(取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差异类会导致数据的变化,内存是变化过的,有中间这个过程)
-
自旋问题。循环时间长开销大:自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一:它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二:它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率
-
只能保证一个共享变量的原子操作。当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作
-
不公平的锁机制:处于阻塞状态的线程,无法立即竞争被释放的锁;而处于自旋状态的线程,很有可能优先获得锁。即CAS无法实现公平锁机制,而Lock体系可以。
AtomicInteger 使用 volatile + CAS(保证线程安全)
AtomicInteger内部维持着一个volatile
的全局变量,且各方法是基于CAS
操作,确保是线程安全的
public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;/*** Creates a new AtomicInteger with the given initial value.** @param initialValue the initial value*/public AtomicInteger(int initialValue) {value = initialValue;}/*** Creates a new AtomicInteger with initial value {@code 0}.*/public AtomicInteger() {}
AtomicInteger使用例子
package com.mb;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;public class Main {static SimpleDateFormat ft = new SimpleDateFormat ("yyyy.MM.dd HH:mm:ss SSS");public static int num = 0;public static AtomicInteger atomicInteger = new AtomicInteger(0);public static void atomicAdd() {atomicInteger.incrementAndGet();}public static void add() {num++;}public synchronized static void addSync() {num++;}private final static int N = 30;public static void main(String[] args) throws Exception {Thread[] threads = new Thread[N];System.out.println(ft.format(new Date()));for(int i=0;i<N;i++){threads[i] = new Thread(()->{try{TimeUnit.MILLISECONDS.sleep(new Random().nextInt(10));int addCnt = 100;for(int j=0;j<addCnt;j++){
// addSync();atomicAdd();}}catch (Exception e){e.printStackTrace();}});threads[i].start();}for(int i=0;i<N;i++) {threads[i].join();}System.out.println(ft.format(new Date()));
// System.out.println("num:" + num);System.out.println("num:" + atomicInteger);}}
/*output
3000 (因为是原子操作)
*/
incrementAndGet()
public final int incrementAndGet() {return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;
}public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
unsafe 的一些方法
Unsafe提供了一些低层次操作,如直接内存访问、线程调度等(不安全,不推荐)
unsafe.objectFieldOffset()
private static Unsafe unsafe = null;
private static long valueOffset;static {try{Class<?> clazz = Unsafe.class;Field f;f = clazz.getDeclaredField("theUnsafe");f.setAccessible(true);unsafe = (Unsafe) f.get(clazz);valueOffset = unsafe.objectFieldOffset(Main.class.getDeclaredField("value"));} catch (IllegalAccessException e) {e.printStackTrace();}catch (SecurityException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}
}
JVM的实现可以自由选择如何实现Java对象的"布局",也就是在内存里Java对象的各个部分放在哪里,包括对象的实例字段和一些元数据之类。sun.misc.Unsafe
里关于对象字段访问的方法把对象布局抽象出来,它提供了objectFieldOffset()
方法用于获取某个字段相对Java对象的“起始地址”的偏移量,也提供了getInt、getLong、getObject之类的方法可以使用前面获取的偏移量来访问某个Java对象的某个字段
compareAndSwapInt
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
即:
boolean compareAndSwapInt(Object obj,long fieldoffset, int expect, int update);
内存值V、旧的预期值A、要修改的值B
当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做并返回false。
即 当要修改obj对象的(fieldoffset)Int
属性值与expect
相同时,则修改(fieldoffset)Int
为update,并返回true
,否则什么都不做,返回false
getIntVolatile
public native int getIntVolatile(Object var1, long var2);
getIntVolatile方法用于在对象指定偏移地址处volatile读取一个int。
unsafe线程安全操作例子程序
public class Main {private static Unsafe unsafe = null;private static long valueOffset;static {try{Class<?> clazz = Unsafe.class;Field f;f = clazz.getDeclaredField("theUnsafe");f.setAccessible(true);unsafe = (Unsafe) f.get(clazz);valueOffset = unsafe.objectFieldOffset(Main.class.getDeclaredField("value"));} catch (IllegalAccessException e) {e.printStackTrace();}catch (SecurityException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}}private volatile int value;public final int get() {return value;}public final void set(int newValue) {value = newValue;}public void addAndIncrease() {int var5;do {var5 = unsafe.getIntVolatile(this, valueOffset);} while(!unsafe.compareAndSwapInt(this, valueOffset, var5, var5 + 1));}public void add() {value ++;}public synchronized void addSync() {value ++;}private final static int N = 30;public static void main(String[] args) throws Exception {Main m = new Main();m.set(2);Thread[] threads = new Thread[N];for(int i=0;i<N;i++){threads[i] = new Thread(()->{try{TimeUnit.MILLISECONDS.sleep(new Random().nextInt(10));int addCnt = 100;for(int j=0;j<addCnt;j++){
// m.add();
// m.addSync();m.addAndIncrease();}}catch (Exception e){e.printStackTrace();}});threads[i].start();}for(int i=0;i<N;i++) {threads[i].join();}System.out.println("value:" + m.get());}}
原子引用(AtomicReference)
对对象
进行原子操作,提供了一种读和写都是原子性的对象引用变量。原子意味着多个线程试图改变同一个AtomicReference(例如比较和交换操作)将不会使得AtomicReference处于不一致的状态。
AtomicReference
和AtomicInteger
非常类似,不同之处就在于AtomicInteger
是对整数的封装,底层采用的是compareAndSwapInt
实现CAS
,比较的是数值是否相等,而AtomicReference
则对应普通的对象引用,底层使用的是compareAndSwapObject
实现CAS
,比较的是两个对象的地址是否相等。也就是它可以保证你在修改对象引用时的线程安全性。
class User{String userName;int age;public User(String userName, int age) {this.userName = userName;this.age = age;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"userName='" + userName + '\'' +", age=" + age +'}';}
}public class Main {public static void main(String[] args) {User z3 = new User("z3", 12);User l4 = new User("l4", 15);AtomicReference<User> atomicReference = new AtomicReference<>();atomicReference.set(z3);boolean b = atomicReference.compareAndSet(z3, l4);System.out.println(b);System.out.println(atomicReference.get().toString());b = atomicReference.compareAndSet(z3, l4);System.out.println(b);System.out.println(atomicReference.get().toString());}}
AtomicStampedReference(用版本解决ABA)
ABA问题
public class Main {static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);public static void main(String[] args) {new Thread(()->{boolean b = atomicReference.compareAndSet(100, 101); // A B ASystem.out.println(Thread.currentThread().getName() + " " + b + " " + atomicReference.get().toString());b = atomicReference.compareAndSet(101, 100);System.out.println(Thread.currentThread().getName() + " " + b + " " + atomicReference.get().toString());}, "t1").start();new Thread(()->{try{TimeUnit.SECONDS.sleep(1);}catch (Exception e){}// t2 修改成功, 另外一个线程从 100 变成 101 又变成了 100, b比较判断是100,所以能修改成功boolean b = atomicReference.compareAndSet(100, 102);System.out.println(Thread.currentThread().getName() + " " + b + " " + atomicReference.get().toString());}, "t2").start();}
}
ABA问题的解决(加上版本)
public class Main {static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);public static void main(String[] args) {new Thread(()->{int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName() + " " + stamp);try{TimeUnit.SECONDS.sleep(1);}catch (Exception e){}boolean b = atomicStampedReference.compareAndSet(100, 101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp() + 1); // A B ASystem.out.println(Thread.currentThread().getName() + " " + b + " " + atomicStampedReference.getStamp());b = atomicStampedReference.compareAndSet(101, 100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp() + 1);System.out.println(Thread.currentThread().getName() + " " + b + " " + atomicStampedReference.getStamp());}, "t1").start();new Thread(()->{// t2 修改成功int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName() + " " + stamp);try{TimeUnit.SECONDS.sleep(4);}catch (Exception e){}boolean b = atomicStampedReference.compareAndSet(100, 102, stamp, stamp + 1);System.out.println(Thread.currentThread().getName() + " " + b + " " + atomicStampedReference.getStamp());}, "t2").start();}}
- output
t1 1
t2 1
t1 true 2
t1 true 3
t2 false 3
t1,t2某时候同一版本
然后t1执行 A->B->A, 不过加上了版本
然后t2判断是有版本变更的,所以CAS操作失败
相关文章:
Java CAS操作
通过前面的学习认识到了CPU缓存,Java内存模型,以及线程安全的原子、可见、顺序三大特性。本文则重点认识CAS操作,这是Java并发编程常见的一个操作,AbstractQueuedSynchronizer基于此操作提供了丰富的同步器和各种锁。 CAS&#x…...
KNIME:开源 AI 数据科学
KNIME(Konstanz Information Miner)是一款开源且功能强大的数据科学平台,由德国康斯坦茨大学的软件工程师团队开发,自2004年推出以来,广泛应用于数据分析、数据挖掘、机器学习和可视化等领域。以下是对KNIME的深度介绍…...
超级强大的压缩和解压工具,免费解压
软件介绍 今天要给大家分享一款超厉害的软件 ——ZArchiver,在我心中,它堪称安卓平台目前最为强大的解压软件。 之前,我一直使用 MT 管理器来解压文件。然而,MT 管理器存在一些局限性。比如在处理解压分卷文件时,它有时…...
代码随想录_栈与队列
栈与队列 232.用栈实现队列 232. 用栈实现队列 使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部。 pop() – 从队列首部移除元素。 peek() – 返回队列首部的元素。 empty() – 返回队列是否为空。 思路: 定义两个栈: 入队栈, 出队栈, 控制出入…...
基于STM32的智能停车场管理系统设计
目录 引言系统设计 硬件设计软件设计 系统功能模块 车辆识别与进出管理模块车位检测与引导模块计费与支付模块数据存储与查询模块远程监控与异常报警模块 控制算法 车牌识别与车辆进出管理算法车位检测与引导算法计费与支付处理算法数据存储与远程反馈算法 代码实现 车辆检测与…...
告别重启!Vue CLI 动态代理配置实战:实现热更新与灵活配置
在前端开发中,代理配置是解决跨域问题的常见手段。尤其是在使用 Vue CLI 进行开发时,我们经常需要通过 devServer.proxy 来配置代理。然而,传统的代理配置通常是静态的,修改后需要重启开发服务器,这在频繁调整代理配置…...
Cocos Creator 3.8 2D 游戏开发知识点整理
目录 Cocos Creator 3.8 2D 游戏开发知识点整理 1. Cocos Creator 3.8 概述 2. 2D 游戏核心组件 (1) 节点(Node)与组件(Component) (2) 渲染组件 (3) UI 组件 3. 动画系统 (1) 传统帧动画 (2) 动画编辑器 (3) Spine 和 …...
【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.28 存储之道:跨平台数据持久化方案
好的,我将按照您的要求生成一篇高质量的Python NumPy文章。以下是第28篇《存储之道:跨平台数据持久化方案》的完整内容,包括目录、正文和参考文献。 1.28 存储之道:跨平台数据持久化方案 目录 #mermaid-svg-n1z37AP8obEgptkD {f…...
chrome源码剖析—UI架构消息机制
Chrome 浏览器的 UI 架构是高度模块化且基于现代图形技术和用户界面设计理念构建的。它的 UI 架构涵盖了窗口、标签页、控件、通知、菜单等组件的管理和交互。Chrome 的 UI 基本上是通过 views 框架和 Aura(Chrome 自己的 UI 层)构建的,后者又…...
面试经典150题——图的广度优先搜索
文章目录 1、蛇梯棋1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、最小基因变化2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、单词接龙3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 1、蛇梯棋 1.1 题目链接 点击跳转到题目位置 1.2 题目描述 给你一…...
Day30-【AI思考】-错题分类进阶体系——12维错误定位模型
文章目录 错题分类进阶体系——12维错误定位模型**一、认知层错误(根源性缺陷)****二、操作层错误(执行过程偏差)****三、心理层错误(元认知障碍)****四、进阶错误(专业级陷阱)** 错…...
利用Edu邮箱解锁Notion Pro,提升学习与工作效率
摘要: 本文将详细介绍如何通过Edu教育邮箱申请教育订阅,从而免费获得Notion Pro版的所有高级功能。此外,我们还将简要提及Edu邮箱的其他福利,如申请Azure 100免费VPS和OpenAI。通过对比Notion免费版和Pro版的差异,你将…...
剑指 Offer II 010. 和为 k 的子数组
comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20010.%20%E5%92%8C%E4%B8%BA%20k%20%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84/README.md 剑指 Offer II 010. 和为 k 的子数组 题目描述 给定一个正整数数组和一个…...
【外文原版书阅读】《机器学习前置知识》2.用看电影推荐的例子带你深入了解向量点积在机器学习的作用
目录 3.3 Where Are You Looking, Vector? The Dot Product 个人主页:Icomi 大家好,我是Icomi,本专栏是我阅读外文原版书《Before Machine Learning》对于文章中我认为能够增进线性代数与机器学习之间的理解的内容的一个输出,希望…...
Vue.js组件开发-实现全屏平滑移动、自适应图片全屏滑动切换
使用Vue实现全屏平滑移动、自适应图片全屏滑动切换的功能。使用Vue 3和Vue Router,并结合一些CSS样式来完成这个效果。 步骤 创建Vue项目:使用Vue CLI创建一个新的Vue项目。准备图片:将需要展示的图片放在项目的public目录下。创建组件&…...
openRv1126 AI算法部署实战之——ONNX模型部署实战
在RV1126开发板上部署ONNX算法,实时目标检测RTSP传输。视频演示地址 rv1126 yolov5 实时目标检测 rtsp传输_哔哩哔哩_bilibili 一、准备工作 1.从官网下载YOLOv5-v7.0工程(YOLOv5的第7个版本) 手动在线下载: Releases ultraly…...
实验作业管理系统的设计与实现
标题:实验作业管理系统的设计与实现 内容:1.摘要 本系统旨在解决当前实验作业管理中存在的问题,提高管理效率和质量。通过对现有系统的调研和分析,我们确定了系统的功能需求和性能要求,并采用了先进的技术和架构进行设计和实现。系统实现了实…...
【愚公系列】《循序渐进Vue.js 3.x前端开发实践》032-组件的Teleport功能
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主&…...
leetcode——二叉树的最大深度(java)
给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:3 示例 2: 输入:root [1,null,2] 输…...
【PyTorch】3.张量类型转换
个人主页:Icomi 在深度学习蓬勃发展的当下,PyTorch 是不可或缺的工具。它作为强大的深度学习框架,为构建和训练神经网络提供了高效且灵活的平台。神经网络作为人工智能的核心技术,能够处理复杂的数据模式。通过 PyTorch࿰…...
自制一个入门STM32 四足机器人具体开发顺序
0 前期准备 1. 知识储备 学习 STM32 微控制器的基础知识,包括 GPIO、定时器、串口通信等外设的使用,可通过官方文档、教程和视频课程进行学习。了解舵机控制原理,因为四足机器人通常使用舵机来实现关节运动。掌握基本的机械结构设计知识&am…...
SpringCloud基础二(完结)
HTTP客户端Feign 在SpringCloud基础一中,我们利用RestTemplate结合服务注册与发现来发起远程调用的代码如下: String url "http://userservice/user/" order.getUserId(); User user restTemplate.getForObject(url, User.class);以上代码就…...
云原生时代,如何构建高效分布式监控系统
文章目录 一.监控现状二.Thanos原理分析SidecarQuerierStoreCompactor 三.Sidecar or ReceiverThanos Receiver工作原理 四.分布式运维架构 一.监控现状 Prometheus是CNCF基金会管理的一个开源监控项目,由于其良好的架构设计和完善的生态,迅速成为了监控…...
WordPress使用(1)
1. 概述 WordPress是一个开源博客框架,配合不同主题,可以有多种展现方式,博客、企业官网、CMS系统等,都可以很好的实现。 官网:博客工具、发布平台和内容管理系统 – WordPress.org China 简体中文,这里可…...
小白爬虫冒险之反“反爬”:无限debugger、禁用开发者工具、干扰控制台...(持续更新)
背景浅谈 小白踏足JS逆向领域也有一年了,对于逆向这个需求呢主要要求就是让我们去破解**“反爬机制”**,即反“反爬”,脚本处理层面一般都是decipher网站对request设置的cipher,比如破解一个DES/AES加密拿到key。这篇文章先不去谈…...
Time Constant | RC、RL 和 RLC 电路中的时间常数
注:本文为 “Time Constant” 相关文章合辑。 机翻,未校。 How To Find The Time Constant in RC and RL Circuits June 8, 2024 💡 Key learnings: 关键学习点: Time Constant Definition: The time constant (τ) is define…...
Python爬虫学习第三弹 —— Xpath 页面解析 实现无广百·度
早上好啊,大佬们。上回使用 Beautiful Soup 进行页面解析的内容是不是已经理解得十分透彻了~ 这回我们再来尝试使用另外一种页面解析,来重构上一期里写的那些代码。 讲完Xpath之后,小白兔会带大家解决上期里百度搜索的代码编写,保…...
JS 正则表达式 -- 分组【详解】含普通分组、命名分组、反向引用
普通分组 使用圆括号 () 来创建分组捕获匹配的内容,通过正则表达式匹配结果的数组来访问这些捕获的内容。 const str "Hello, World!"; const regex /(Hello), (World)!$/; const match str.match(regex);if (match) {console.log("完整匹配结果…...
Leetcode刷题-不定长滑动窗口
分享丨【题单】滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环) - 力扣(LeetCode) 3090 class Solution:def maximumLengthSubstring(self, s: str) -> int:c Counter()res 0rk -1for i in range(len(s)):i…...
【Rust自学】15.6. RefCell与内部可变性:“摆脱”安全性限制
题外话,这篇文章一共4050字,是截止到目前为止最长的文章,如果你能坚持读完并理解,那真的很强! 喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以…...
护眼好帮手:Windows显示器调节工具
在长时间使用电脑的过程中,显示器的亮度和色温对眼睛的舒适度有着重要影响。传统的显示器调节方式不仅操作繁琐,而且在低亮度下容易导致色彩失真。因此,今天我想为大家介绍一款适用于Windows系统的护眼工具,它可以帮助你轻松调节显…...
使用 OpenResty 构建高效的动态图片水印代理服务20250127
使用 OpenResty 构建高效的动态图片水印代理服务 在当今数字化的时代,图片在各种业务场景中广泛应用。为了保护版权、统一品牌形象,动态图片水印功能显得尤为重要。然而,直接在后端服务中集成水印功能,往往会带来代码复杂度增加、…...
36、【OS】【Nuttx】OSTest分析(2):环境变量测试
背景 2025.1.29 蛇年快乐! 接之前wiki 35、【OS】【Nuttx】OSTest分析(1):stdio测试(五) 已经分析完了第一个测试项,输入输出端口测试,接下来分析下环境变量测试,也比较…...
C++并发编程指南04
文章目录 共享数据的问题3.1.1 条件竞争双链表的例子条件竞争示例恶性条件竞争的特点 3.1.2 避免恶性条件竞争1. 使用互斥量保护共享数据结构2. 无锁编程3. 软件事务内存(STM) 总结互斥量与共享数据保护3.2.1 互斥量使用互斥量保护共享数据示例代码&…...
Java实现LRU缓存策略实战
实现LRU模型选择LRU缓存回收算法集成Google Guava(LRU缓存策略)插件Google Guava(LRU策略)缓存示例总结LRU(Least Recently Used,最近最少使用)缓存是一种常见的缓存淘汰策略。它的基本思想是优先保留最近被访问过的数据,淘汰最久未被访问的数据。这种策略的目的是为了…...
三个不推荐使用的线程池
线程池的种类 其实看似这么多的线程池,都离不开ThreadPoolExecutor去创建,只不过他们是简化一些参数 newFixedThreadPool 里面全是核心线程 有资源耗尽的风险,任务队列最大长度为Integer.MAX_VALUE,可能会堆积大量的请求ÿ…...
Golang 并发机制-1:Golang并发特性概述
并发是现代软件开发中的一个基本概念,它使程序能够同时执行多个任务,从而提高效率和响应能力。在本文中,我们将探讨并发性在现代软件开发中的重要性,并深入研究Go处理并发任务的独特方法。 并发的重要性 增强性能 并发在提高软…...
Flink中的时间和窗口
在批处理统计中,我们可以等待一批数据都到齐后,统一处理。但是在实时处理统计中,我们是来一条就得处理一条,那么我们怎么统计最近一段时间内的数据呢?引入“窗口”。 所谓的“窗口”,一般就是划定的一段时…...
Alfresco Content Services dockerCompose自动化部署详尽操作
Alfresco Content Services docker社区部署文档 Alfresco Content Services简介 官方说明书 https://support.hyland.com/r/Alfresco/Alfresco-Content-Services-Community-Edition/23.4/Alfresco-Content-Services-Community-Edition/Using/Content/Folder-rules/Defining-…...
吴恩达深度学习——深层神经网络
来自https://www.bilibili.com/video/BV1FT4y1E74V,仅为本人学习所用。 符号约定 对于该深层网络,有四层,包含三个隐藏层和一个输出层。 隐藏层中,第一层有五个单元、第二层有五个单元,第三层有三个单元。标记 l l l…...
【算法设计与分析】实验1:字符串匹配问题的算法设计与求解
目录 一、实验目的 二、实验环境 三、实验内容 四、核心代码 五、记录与处理 六、思考与总结 七、完整报告和成果文件提取链接 一、实验目的 给定一个文本,在该文本中查找并定位任意给定字符串。 1、深刻理解并掌握蛮力法的设计思想; 2、提高应用…...
C语言二级题解:查找字母以及其他字符个数、数字字符串转双精度值、二维数组上下三角区域数据对调
目录 一、程序填空题 --- 查找字母以及其他字符个数 题目 分析 二、程序修改 --- 数字字符串转双精度值 题目 分析 小数位字符串转数字 三、程序设计 --- 二维数组上下三角区域数据对调 题目 分析 前言 本文来讲解: 查找字母以及其他字符个数、数字字符串…...
Git进阶之旅:Git 配置信息 Config
Git 配置级别: 仓库级别:local [ 优先级最高 ]用户级别:global [ 优先级次之 ]系统级别:system [ 优先级最低 ] 配置文件位置: git 仓库级别对应的配置文件是当前仓库下的 .git/configgit 用户级别对应的配置文件时用…...
Qwen2-VL:在任何分辨率下增强视觉语言模型对世界的感知 (大型视觉模型 核心技术 分享)
摘要 我们推出了Qwen2-VL系列,这是对之前Qwen-VL模型的高级升级,重新定义了视觉处理中的常规预设分辨率方法。Qwen2-VL引入了Naive Dynamic Resolution机制,使模型能够动态地将不同分辨率的图像转换为不同的视觉令牌数量。这种方法允许模型生成更高效和准确的视觉表示,紧密…...
【C语言】在Windows上为可执行文件.exe添加自定义图标
本文详细介绍了在 Windows 环境下,如何为使用 GCC 编译器编译的 C程序 添加自定义图标,从而生成带有图标的 .exe 可执行文件。通过本文的指导,读者可以了解到所需的条件以及具体的操作步骤,使生成的程序更具专业性和个性化。 目录 1. 准备条件2. 具体步骤步骤 1: 准备资源文…...
记录 | Docker的windows版安装
目录 前言一、1.1 打开“启用或关闭Windows功能”1.2 安装“WSL”方式1:命令行下载方式2:离线包下载 二、Docker Desktop更新时间 前言 参考文章:Windows Subsystem for Linux——解决WSL更新速度慢的方案 参考视频:一个视频解决D…...
FortiOS 存在身份验证绕过导致命令执行漏洞(CVE-2024-55591)
免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...
系统思考—心智模式
“我们的大脑对连贯性的渴望远胜于对准确性的追求。”—诺贝尔经济学得主丹尼尔卡尼曼 在面对复杂的决策时,我们往往更倾向于寻找那些能够迅速串联起来的信息,而非深入挖掘每一个细节的真实性。这种倾向在日常生活中或许能帮助我们迅速作出决策…...
【信息系统项目管理师-选择真题】2008上半年综合知识答案和详解
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 【第1题】【第2题】【第3题】【第4题】【第5题】【第6题】【第7~8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16~20题】【第21题】【第22题】【第23题】【第24题】【第25题…...
深入理解三高架构:高可用性、高性能、高扩展性的最佳实践
引言 在现代互联网环境下,随着用户规模和业务需求的快速增长,系统架构的设计变得尤为重要。为了确保系统能够在高负载和复杂场景下稳定运行,"三高架构"(高可用性、高性能、高扩展性)成为技术架构设计中的核…...