多线程(进阶续~)(内涵面试题)
目录
一、JUC 的常见类
1. Callable 接口
2. ReentrantLock
ReentrantLock 的用法:
ReentrantLock 和 synchronized 的区别:
何时使用何锁:
3. 原子类
4. 线程池
ExecutorService 和 Executors
ThreadPoolExecutor
5. 信号量 Semaphore
6. CountDownLatch
7. 相关面试题
二、线程安全的集合类
1. 多线程环境使用 ArrayList
2. 多线程环境使用队列
3. 多线程环境使用哈希表
1) Hashtable
2) ConcurrentHashMap
4. 相关面试题
这篇博客之前还有一篇 多线程进行 的一篇博客:
直达地址:
多线程(进阶)(内涵面试题)-CSDN博客
欢迎观看~让我们共同进步!!!💓💓💓💓💓💓
一、JUC 的常见类
1. Callable 接口
Callable 是一个 interface。相当于把线程封装了一个 "返回值"。
直接上代码看如何使用 这个 Callable接口:
创建线程 1+2+3+.....+1000,使用Callable版本
• 创建一个匿名内部类,实现 Callable 接口,Callable 带有泛型参数。泛型参数表示返回值的类型
• 重写 Callable 的 call 方法,完成累加的过程。直接通过返回值返回计算结果。
• 把 callable 实例使用FutureTask包装⼀下。
• 创建线程,线程的构造方法传入FutureTask。此时新线程就会执行FutureTask内部的Callable的 call 方法,完成计算。计算结果就放到了FutureTask对象中。
• 在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕。并获取到FutureTask中的结果。
代码如下:
public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<Integer> callable = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 1; i <= 1000; i++) {sum += i;}return sum;}};FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread t = new Thread(futureTask);t.start();int result = futureTask.get();System.out.println(result);}
}
可以看到,使用 Callable 和 FutureTask 之后,代码简化了很多,也不必手动写线程同步代码了。
理解 Callable
Callable 和 Runnable 相对,都是描述一个 "任务"。Callable 描述的是带有返回值的任务,Runnable描述的是不带返回值的任务。
Callable 通常需要搭配 FutureTask 来使用。FutureTask 用来保存 Callable 的返回保存。因为Callable往往是另一个线程中执行的,啥时候执行完并不确定。
FutureTask 就可以负责这个等待结果出来的工作。
理解 FutureTask
当去吃一些带有号码牌的食品的时候,比如麻辣烫,当选好菜之后,会给你一个 小牌或者是一个 号码。这个 小牌或者号码就是 FutureTask。后面需要凭借这个 小牌或者号码 取餐。
2. ReentrantLock
可重入互斥锁。和 synchronized 定位类似,都是用来实现互斥效果,保证线程安全。
ReentrantLock 也是可重入锁。
ReentrantLock 的用法:
• lock(): 加锁,如果获取不到锁就死等。
• trylock(超时时间): 加锁,如果获取不到锁,等待一定的时间之后就放弃加锁。
• unlock(): 解锁。
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {// working
} finally {lock.unlock();
}
ReentrantLock 和 synchronized 的区别:
• synchronized 是一个关键字,是 JVM 内部实现的。ReentrantLock 是标准库的一个类,在JVM外实现的(基于Java实现)。
• synchronized 使用是不需要手动释放锁。ReentrantLock 使用是需要手动释放。使用起来更灵活,但是也容易遗漏 unlock。
• synchronized 在申请锁失败时,会死等。ReentrantLock 可以通过 trylock 的方式等待一段时间就放弃。
• synchronized 是非公平锁,ReentrantLock 默认是非公平锁。可以通过构造方法传入一个 true 开启公平锁模式。代码如下:
// ReentrantLock 的构造⽅法
public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();
}
• 更强大的唤醒机制。synchronized 是通过 Object 的 wait/notify 实现等待-唤醒。每次唤醒的是一个随机等待的线程。ReentrantLock 搭配 Condition 类实现等待-唤醒,可以更精确控制唤醒某个指定的线程。
何时使用何锁:
• 锁竞争不激烈的时候,使用 synchronized,效率更高,自动释放更方便。
• 锁竞争激烈的时候,使用 ReentrantLock,搭配 trylock 更灵活控制加锁的方式,而不是死等。
• 如果需要使用公平锁,使用 ReentrantLock。
3. 原子类
原子类内部用的是 CAS 实现,所以性能要比加锁实现 i++ 高很多。原子类有以下几个:
• AtomicBoolean
• AtomicInteger
• AtomicIntegerArray
• AtomicLong
• AtomicReference
• AtomicStampedRefernce
以 AtomicInteger 举例,常用方法有:
1. addAndGet(int delta); i += delta;
2. decrementAndGet(); --i;
3. getAndDecrement(); i--;
4. incrementAndGet(); ++i;
5. getAndIncrement(); i++;
4. 线程池
虽然创建销毁线程比创建销毁进程更轻量,但是在频繁创建销毁线程的时候还是会比较抵消。
线程池就是为了解决这个问题。如果某个线程不在使用了,就不是真正把线程释放,而是放到一个 "池子" 中,下次如果需要用到线程就直接从池子中取,不必通过系统来创建了。
ExecutorService 和 Executors
代码示例:
• ExecutorService 表示一个线程池实例。
• Executors 是一个工厂类,能够常见出几种不同风格的线程池。
• ExecutorService 的submit 方法能够向线程池中提交若干个任务。
public class Test {public static void main(String[] args) {ExecutorService pool = Executors.newFixedThreadPool(10);pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello");}});}
}
Executors 创建线程池的几种方式
• newFixedThreadPool:创建固定线程数的线程池。
• newCachedThreadPool:创建线程数目动态增长的线程池。
• newSingleThreadExecutor:创建质保函单个线程的线程池。
• newScheduledThreadPool:设定 延迟时间后执行命令,或者定期执行命令。是进阶版的 Timer
Executors 本质上是 ThreadPoolExector 类的封装。
ThreadPoolExecutor
ThreadPoolExecutor 提供了更多的可选参数,可以进一步细化线程池的行为设定
ThreadPoolExecutor 的构造方法:
这里的 构造方法 中参数的理解是非常重要的。
corePoolSize: 核心线程数。(至少有多少个线程。线程池一创建,这些线程也要随之创建。直至整个线程池销毁,这些线程才会销毁)
maximumPoolSize: 最大线程数。(核心线程数 + 非核心线程数),(对于非核心线程数是自适应的在不繁忙时候就销毁,繁忙就再进行创建)
keepAliveTime: 非核心线程允许空闲的最大时间
unit: 枚举类型,枚举的是keepAliveTime 的时间单位,是秒、分钟花式其他值
workQueue: 传递任务的阻塞队列。(选择使用数组/链表,指定capacity,指定是否带有优先级/比较规则) (线程池,本质上也是 生产者消费者模型。调用 submit 就是在生产任务,线程池里的线程就是在消费任务)
threadFactory: 创建线程的工厂,参与具体的创建线程工作。(这是一种设计模式——工厂模式,统一的构造并初始化线程,用来弥补构造方法的缺陷的) (和单例模式是并列的关系)
工厂模式:
其工厂方法的核心就是通过 静态方法,把构造对象 new 的过程,各种属性初始化的过程,封装起来了。其 提供了多组静态方法,实现不同情况的构造。(提供工厂方法的类,就称之为 "工厂类")
RejectedExecutionHandler: 拒绝策略。
这个是线程池七个参数中,最重要的,最复杂的,在面试中也是最想要听到的。
submit 把任务添加到任务队列中,任务队列是阻塞队列,队列满了,再添加,进行阻塞,一般来说不希望程序阻塞太多。对于线程池来说,发现入队列操作是,队列满了不会触发"入队列策略",不会真阻塞,而是执行拒绝策略相关的代码。
Java标准库,也提供了另一组类,针对 ThreadPoolExecutor 进行了进一步封装,简化线程池的使用。也是基于 工厂设计模式。
代码如下:
public class Test {public static void main(String[] args) {//ExecutorService threadPool = Executors.newFixedThreadPool(3);// 固定线程数ExecutorService threadPool = Executors.newCachedThreadPool();// 不固定,自动增加for (int i = 0; i < 1000; i++) {int id = i;threadPool.submit(() -> {System.out.println("hello " + id + ", " + Thread.currentThread().getName());});}// shutdown 能够把线程池里的线程全部关闭,但是不能保证线程池内的任务一定能全部执行完毕。// 所以,如果需要等待线程池内的任务全部执行完毕,需要调用 awaitTermination 方法。threadPool.shutdown();}
}
5. 信号量 Semaphore
信号量,用来表示 "可用资源的个数"。本质上就是一个计数器。
信号量的理解:
可以把信号量想象成是停车场的展示牌,当前有100个车位,表示存在100个可用资源。
当有车开进去的时候,就相当于申请一个可用资源,可用车位就-1(这个称为信号量的P操作)
当有车开出来的时候,就相当于释放一个可用资源,可用车位就+1(这个称为信号量的V操作)
如果计数器的值已经是0了,还在尝试申请资源,就会阻塞等待,直到有其他线程释放资源。
Semaphore 的 PV 操作中的加减计数器操作都是原子的,可以在多线程环境下直接使用。
代码示例:
• 创建 Semaphore 示例,初始化为4,表示存在4个可用资源
• acqurie 放啊表示申请资源(P 操作),release 方法表示释放资源(V 操作)
• 创建 20 个线程,每个县城都尝试申请资源,sleep 1秒之后,释放资源
public class Test {public static void main(String[] args) {Semaphore semaphore = new Semaphore(4);Runnable runnable = new Runnable() {@Overridepublic void run() {try {System.out.println("申请资源");semaphore.acquire();System.out.println("获取到资源,使用一秒");Thread.sleep(1000);System.out.println("释放资源"); semaphore.release();}catch (InterruptedException e) {e.printStackTrace();}}};for(int i = 0;i < 20;i++) {Thread t = new Thread(runnable);t.start();}}
}
6. CountDownLatch
同时等待 N 个任务执行结束。
比如:跑步比赛,选手们只有当哨声响才能同时出发,当所有选手都通过终点,才能公布成绩。
• 构造 CountDownLatch 示例,初始化10 表示有 10 个任务需要完成
• 每个任务执行完毕,都调用 latch.countDown()。在 CountDownLatch 内部的计数器同时自减
• 主线程中使用 latch.await(); 阻塞等待所有任务执行完毕,相当于计数器等于0时
public class Test {public static void main(String[] args) throws InterruptedException {// 现在把整个任务拆成 10 个部分. 每个部分视为是一个 "子任务".// 可以把这 10 个子任务丢到线程池中, 让线程池执行.// 当然也可以安排 10 个独立的线程执行.// 构造方法中传入的 10 表示任务的个数.CountDownLatch latch = new CountDownLatch(10);ExecutorService executor = Executors.newFixedThreadPool(4);for (int i = 0; i < 10; i++) {int id = i;executor.submit(() -> {System.out.println("子任务开始执行: " + id);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("子任务结束执行: " + id);latch.countDown();});}// 这个方法阻塞等待所有的任务结束// 此处的 a => alllatch.await();System.out.println("所有任务执行完毕");executor.shutdown();}
}
7. 相关面试题
1)线程同步的方式有哪些?
synchronized、ReentrantLock、Semaphone 等都可以用于线程同步。
2)为什么有了 synchronized 还需要 juc下的 lock?
以ReentrantLock 为例:
• synchronized 使用是不需要手动释放锁。ReentrantLock 使用时需要手动释放,使用起来更灵活
• synchronized 在申请锁失败时,会死等。ReentrantLock 可以通过 trylock 的方式等待一段时间就放弃。
• synchronized 是非公平锁,ReetrantLock 默认是非公平锁,可以通过构造方法传入一个 true 开启公平锁模式。
• synchronized 是通过 Objec 的wait / notfiy 实现 等待-唤醒。每次唤醒的是一个随机等待的线程。ReentrantLock 代培 Condaition 类实现 等待-唤醒,可以更精确控制唤醒某个指定的线程。
3)信号量是否听过?在哪些场景下使用过?
信号量,用来表示 "可用资源的个数" 本质上就是一个计数器。
使用信号量可以实现 "共享锁" 比如某个资源允许 3 个线程同时使用,那么就可以使用 P 操作作为加锁,V 操作作为解锁,前三个线程的 P 操作都能顺利返回,后序线程在进行 P 操作就会阻塞等待,直至前面的线程执行了 V 操作。
二、线程安全的集合类
原来的集合类,大部分都不是线程安全的。
Vector、Stack、HashTable,是线程安全的(但不建议使用),其他集合类不是线程安全的
1. 多线程环境使用 ArrayList
1)自行加锁。「推荐」
使用 synchronized 或者 ReentrantLock。但是要分析清楚,要把哪些代码打包到一起,成为一个 "原子" 操作。
2)Collections.synchronizedList(new ArrayList); 「不是很推荐」(因为加锁有代价)
返回的 List 的各种关键方法都带有 synchronized。是基于 synchronized 进行线程同步的 List.synchronizedList 的关键操作。
3)使用 CopyOnWriteArrayList
CopyOnWrite容器即写时复刻的容器。
• 当往一个容器添加元素的时候,不直接王当前容器添加,而是现将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素。
• 添加完元素之后,在将原容器的引用指向新的容器。
这样做的好处就是可以对 CopyOnWrite容器进行并发的读,并不需要加锁,因为当前容器不会添加任何元素。
所以 CopyOnWrite容器是一种读写分离的思想,读和写在不同的容器中。
缺点:
1.数组非常的大,非常低效,占用内存较多。
2.新写的数据不能被第一时间读取到。如果多个线程同时修改,也容易出现问题。
优点:
在读多写少的场景下,性能很高,不需要加锁竞争。比如:服务器进行重现加载配置的时候。
2. 多线程环境使用队列
1)ArrayBlockingQueue
基于数组实现的阻塞队列
2)LinkedBlockingQueue
基于链表实现的阻塞队列
3)PriorityBlockingQueue
基于堆实现的带优先级的阻塞队列
4)TransferQueue
最多只包含一个元素的阻塞队列
3. 多线程环境使用哈希表
HashMap 本身不是线程安全的。
在多线程环境下使用哈希表可以使用:
• Hashtable
• ConcurrentHashMap
1) Hashtable
Hashtable只是简单的把关键方法加上了 synchronized 关键字。
上面展示的只是一部分方法。
这就相当于直接针对 Hashtable 对象本身加锁。
• 如果多线程访问同一个 Hashtable 就会直接造成锁冲突。
• size 属性也是通过 synchronized 来控制同步的,所以是比较慢的。
• 一旦触发扩容,就由多线程完成整个扩容过程。这个过程会涉及到大量的元素拷贝,效率会非常低。
2) ConcurrentHashMap
相比于 Hashtable 做出了一系列的改进和优化。
• 读操作没有加锁(但是使用了 volatile 保证从内存读取结果),只对写操作进行加锁。加锁的方式任然是使用 synchronized,但是不是锁整个对象,而是 "锁桶" (用每个链表的头结点作为锁对象),大大降低了锁冲突的概率。
• 充分利用了 CAS 特性。比如 size 属性通过 CAS 来更新。避免出现重量级锁的情况。
• 优化了扩容方式: 化整为零
○ 发现组要扩容的线程,只需要创建一个新的数组,同时值搬几个元素过去。
○ 扩容期间,新老数组同时存在。
○ 后续每个来操作 ConcurrentHashMap 的线程,都会参与搬家的过程。每个操作负责搬运一小部分元素。
○ 搬完最后一个元素再把老数组删掉
○ 这个期间,插入只往新数组加。查找需要同时查 新数组和老数组。
这样之后:
如果修改的两个元素,在不同的链表(哈希桶)上,本身就不涉及线程安全问题(修改不同的变量)
如果修改同一个链表上的两个元素,可能存在线程安全问题,比如把这俩元素插入到同一个元素后面,就可能产生竞争。
ConcurrentHashMap 核心优化点;
(1) 把锁整个表 变成 锁桶
(2) 使用 原子类 针对 size 进行维护
(3) 针对哈希扩容的场景
化整为零
确保每个操作的加锁时间不要太长
4. 相关面试题
1)ConcurrentHashMap的读是否要加锁,为什么?
读操作没有加锁。目的是为了进一步降低锁冲突的概率。为了保证读到刚修改的数据,搭配了 volatile 关键字。
2)介绍下 ConcurrentHashMap的锁分段技术?
就是把若干个 哈希桶 分成一个 "段",针对每个段分别加锁。目的是为了降低锁竞争的概率。当然两个线程访问的数据恰好在同一个段上的时候,才会触发锁竞争。
3)Hashtable、HashMap和ConcurrentHashMap 之间的区别?
HashMap:线程不安全。key 允许为 null
Hashtable:线程安全。使用 synchronized 锁 Hashtable 对象,效率较低。key 不允许为null
ConcurrentHashMap:线程安全。使用 synchronized 锁每个链表头结点,锁冲突概率低,充分利用CAS机制。优化了扩容方式。key 不允许为 null。
感觉文章不错的话,期待你的一键三连哦,你的鼓励就是我的动力,让我们一起加油,顶峰相见。拜拜喽~~我们下次再见💓💓💓💓💓💓💓💓💓💓💓💓
相关文章:
多线程(进阶续~)(内涵面试题)
目录 一、JUC 的常见类 1. Callable 接口 2. ReentrantLock ReentrantLock 的用法: ReentrantLock 和 synchronized 的区别: 何时使用何锁: 3. 原子类 4. 线程池 ExecutorService 和 Executors ThreadPoolExecutor 5. 信号量 Semaphore 6. C…...
OpenGL shader开发实战学习笔记:第十一章 立方体贴图和天空盒
1. 立方体贴图和天空盒 1.1. 什么是立方体贴图 立方体贴图(Cube Map)是一种纹理,它由六个纹理图像组成,每个纹理图像对应一个方向。这些方向通常是立方体的六个面,分别是“前面”,“后面”,“…...
双指针算法(二)
目录 一、力扣611——有效三角形的个数 二、牛客网3734——和为S的两个数字 三、力扣15——三数之和 四、力扣18——四数之和 一、力扣611——有效三角形的个数 题目如下: 这里我们先认识如何判断是个三角形,ab>c,ac>b,bc>a即为三角形 这里…...
docker Windows 存放位置
docker Windows 存放位置 镜像文件层可能是这 docker的overlay2中存的都是什么and如何清理/var/lib/docker/overlay2_docker overlay 是什么目录-CSDN博客 存的是我们的镜像文件和容器内的文件 \\wsl.localhost\docker-desktop\mnt\docker-desktop-disk\data\docker\overla…...
每日一题(小白)暴力娱乐篇31
首先分析一下题意,需要求出2024的因子,因为我们要求与2024互质的数字,为什么呢?因为我们要求互质说直白点就是我和你两个人没有中间人,我们是自然而然认识的,那我们怎么认识呢,就是直接见面对吧…...
FastAPI与SQLAlchemy数据库集成
title: FastAPI与SQLAlchemy数据库集成 date: 2025/04/17 15:33:34 updated: 2025/04/17 15:33:34 author: cmdragon excerpt: FastAPI与SQLAlchemy的集成通过创建虚拟环境、安装依赖、配置数据库连接、定义数据模型和实现路由来完成。核心模块包括数据库引擎、会话工厂和声…...
SQL刷题记录贴
1.题目:现在运营想要对用户的年龄分布开展分析,在分析时想要剔除没有获取到年龄的用户,请你取出所有年龄值不为空的用户的设备ID,性别,年龄,学校的信息。 错误:select device_id,gender,age,un…...
消息队列实际结点数与计数器不一致问题分析
问题描述 协议栈 PDCP线程任根据外部消息,维护一个链表式的PDCP PDU消息队列,以及一个变量count来记录消息队列中结点数。 当收到 从NG接口业务数据时,PDCP线程会向PDCP PDU消息队列中添加大量节点,消息队列的count值相应的增加…...
AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年4月17日第55弹
从今天开始,咱们还是暂时基于旧的模型进行预测,好了,废话不多说,按照老办法,重点8-9码定位,配合三胆下1或下2,杀1-2个和尾,再杀6-8个和值,可以做到100-300注左右。 (1)定…...
C++23 新特性:std::size_t 字面量后缀 Z/z
在 C23 中,引入了一个非常实用的新特性:为 std::size_t 类型的字面量提供了新的后缀 Z 和 z。这一改进使得在代码中声明和使用 std::size_t 类型的字面量变得更加直观和便捷。 1. 背景与动机 在之前的 C 标准中,std::size_t 是一种非常常用…...
【裁员感想】
裁员感想 今天忽然感觉很emo 因为知道公司要裁员 年中百分之10 年末百分十10 我知道这个百分20会打到自己 所以还挺不开心的 我就想起 我的一个亲戚当了大学老师 我觉得真的挺好的 又有寒暑假 又不是很累 薪资也不低 又是编制 同时也觉得自己很失败 因为对自己互联网的工作又…...
CSS例子 > 图片瀑布流布局(vue2)
<template><div class"container"><!-- 临时容器用于计算高度 --><div v-if"!isLayoutReady" class"temp-container"><divv-for"(item, index) in list":key"temp- index":ref"(el) > …...
Python 获取淘宝券后价接口的详细指南
在电商领域,淘宝作为国内领先的电商平台,提供了丰富的商品和优惠活动。对于开发者来说,获取淘宝商品的券后价是一个极具价值的功能,可以帮助用户更好地进行购物决策,同时也为相关应用和服务提供了数据支持。本文将详细…...
零服务器免备案!用Gitee代理+GitHub Pages搭建个人博客:绕过443端口封锁实战记录
#GitHub Pages #Gitee代理 #SSH密钥管理 #Jekyll博客 #网络穿透 场景:自己的电脑没有添加github的ssh代理,只有gitee的代理 实现效果,在公网可以运行个人博客。在本地更改内容后公网同步更新。 最开始的模板 最终实现的博客模板࿱…...
如何新建一个空分支(不继承 master 或任何提交)
一、需求分析: 在 Git 中,我们通常通过 git branch 来新建分支,这些分支默认都会继承当前所在分支的提交记录。但有时候我们希望新建一个“完全干净”的分支 —— 没有任何提交,不继承 master 或任何已有内容,这该怎么…...
[终极版]Javascript面试全解
this指向 执行上下文 是代码执行时的运行环境作用域 是变量和函数的可访问性规则(静态);全局、函数和块状;内层可访问外层,外层不能访问内层词法环境 是实现作用域的引擎内部机制(静态) 执行上…...
day30图像处理OpenCV
文章目录 一、图像预处理9. 图像掩膜9.1 制作掩膜9.2 与运算1.原理2.语法 9.3 颜色替换9.4案例 一、图像预处理 9. 图像掩膜 创建的掩膜方便我们对目标区域进行操作。 9.1 制作掩膜 掩膜通常是一个二值化图像,并且与原图像的大小相同。其中目标区域被设置为1&am…...
蓝桥杯 10.拉马车
拉马车 原题目链接 题目描述 小时候你玩过纸牌游戏吗? 有一种叫做 “拉马车” 的游戏,规则简单但非常吸引小朋友。 游戏规则简述如下: 假设参加游戏的小朋友是 A 和 B,游戏开始时,他们得到的随机纸牌序列如下&am…...
Java学习总结-Junit单元测试
单元测试: 就是针对最小功能的单元:方法,编写测试代码对其进行正确性测试。 之前我们怎么测试的:在main方法中调用其他方法,一个方法测试失败可能导致其他方法得不到测试,无法得到测试报告。 Junit单元测…...
代理IP:城市文化IP打造的隐形加速器
目录 一、解码代理IP:数字时代的"变身术" 1.1 工作原理探秘 1.2 主要类型对比 二、城市文化IP的打造密码 2.1 核心要素拆解 2.2 成功案例启示 三、代理IP的五大赋能场景 3.1 文化数据采集 3.2 目标市场定位 3.3 品牌传播突破 3.4 版权保护监控 …...
链式数据存储系统
目录 系统说明 服务端的模块设计 存储数据说明 服务端设计-程序入口(main) 数据库的连接-mysql包的编写 数据的加密-hash文件的编写 数据传递格式-proto文件的编写 具体实现方法-controller包的编写 日志的打印-logs包的编写 扩展服务端 系统说…...
《理解 Java 泛型中的通配符:extends 与 super 的使用场景》
大家好呀!👋 今天我们要聊一个让很多Java初学者头疼的话题——泛型通配符。别担心,我会用最通俗易懂的方式,带你彻底搞懂这个看似复杂的概念。准备好了吗?Let’s go! 🚀 一、为什么我们需要泛型通配符&…...
Scala 入门指南
Scala 入门指南 目录 简介环境搭建基础语法面向对象编程函数式编程集合模式匹配特质隐式转换并发编程与 Java 互操作最佳实践常见问题 简介 Scala 是一种多范式编程语言,结合了面向对象编程和函数式编程的特性。它运行在 JVM 上,与 Java 完全兼容&am…...
GESP2025年3月认证C++八级( 第一部分选择题(11-15))
杨辉三角形: #include <iostream> using namespace std;#define N 35 // 最多支持输出 35 行 int a[N]; // 一维数组,用于存储当前行的杨辉三角数int main() {int n;cin >> n; // 输入要输出的行数for (int i 0; i < n; i) {a[i] …...
Dynamics 365 Business Central Master Data Managerment Setup 主数据管理
#Dynamics 365 BC ERP# #Navision# 引言 在BC中除了之前有一个章节提到的用Code 同步资料, 也可以用内置主数据管理功能来同步资料。 Master Data Management Setup 设置Source Company 为 主要管理主数据的公司 Synchronization Tables 设置需要同步的Table 这…...
深入理解 requestIdleCallback 与大数据加载优化
使用 requestIdleCallback 优化大批量 DOM 操作 —— 以加载 100 万条数据为例 在前端开发中,如果你尝试在短时间内往 DOM 中添加大量元素,比如一次性插入 100 万条数据,页面极有可能卡顿甚至直接崩溃。为了解决这一性能问题,我们…...
【MySQL】索引运算与NULL值问题详解:索引字段应尽量 NOT NULL ,NULL值不能参与部分索引运算
索引运算与NULL值问题详解 不能参与的"部分索引运算"指什么? 这里的"部分索引运算"指的是索引列在某些特定操作或条件下无法被MySQL优化器有效利用的情况,特别是当字段包含NULL值时。主要包括以下几种情况: 1. 比较运…...
STM32 F103 标准库CH452A 4线 数码管驱动芯片显示数码管
公司生产测试需要统一去检查这版CH452A的好坏,网上找了一下没有现成可以用的4线CH452A的驱动程序,所以直接就肝了移植官方的51程序到stm32上面去,亲测可以使用!! 文末有代码 测试图片: 如你所见我测了一堆…...
Vue 和 Spring boot 和 Bean 不同生命周期
一、Vue 组件生命周期 父子组件生命周期顺序: 创建时: 父 beforeCreate → 父 created → 父 beforeMount → 子组件生命周期 → 父 mounted 更新时: 父 beforeUpdate → 子组件更新 → 父 updated。 销毁时: 父 beforeDestroy…...
期货数据API对接实战指南
一、期货数据接口概述 StockTV提供全球主要期货市场的实时行情与历史数据接口,覆盖以下品种: 商品期货:原油、黄金、白银、铜、天然气、农产品等金融期货:股指期货、国债期货特色品种:马棕油、铁矿石等区域特色期货 …...
Flask(2): 在windows系统上部署项目2
4 创建并激活虚拟环境 虚拟环境非常有用,可以将多个项目隔离开来。根据我看的教程,貌似以前有多种创建方式,后来官方自带了。目前我就用官方的方式。 4.1 创建虚拟环境 创建部署文件夹(假如目录为d:\project01),在命令提示…...
Java 中 Synchronized如何保证可见性
在 Java 多线程编程中,可见性问题是指一个线程对共享变量的修改,其他线程能够立即看到。如果没有适当的同步机制,可能会出现线程 A 修改了共享变量的值,但线程 B 仍然使用的是修改前的值,导致程序出现错误。synchroniz…...
33、Python单元测试与pytest框架从入门到精通
Python单元测试与pytest框架从入门到精通 引言 在软件开发领域,完善的测试体系是保证代码质量的生命线。本文将深入探讨Python单元测试的核心技术,从标准库unittest到功能强大的pytest框架,通过20个代码示例展示测试驱动开发(TD…...
mvccc
. MVCC (多版本并发控制) 概念: MVCC 是一种并发控制技术,用于在数据库中实现并发事务的读写操作,同时保证事务的隔离性。MVCC 的核心思想是,在数据库中维护数据的多个版本,每个事务在读取数据时,读取的是…...
ONLYOFFICE深度解锁系列.2-Excel 跨文件数据整合实战指南-可道云的另一个严重bug
一、为什么需要跨文件数据整合? 在企业办公和团队协作中,数据往往分散在不同文件中。传统复制粘贴方式存在三大痛点: 版本混乱:源数据更新后需反复同步 错误风险:手动操作易造成数据偏差 效率低下:多文件…...
如何对Flutter应用程序进行单元测试
Flutter单元测试完全指南:从基础到高级实践 面试求职资源 面试试题小程序:涵盖测试基础、Linux操作系统、MySQL数据库、Web功能测试、接口测试、APPium移动端测试、Python知识、Selenium自动化测试相关、性能测试、计算机网络知识、Jmeter、HR面试等内…...
多模态大语言模型arxiv论文略读(二十四)
VCoder: Versatile Vision Encoders for Multimodal Large Language Models ➡️ 论文标题:VCoder: Versatile Vision Encoders for Multimodal Large Language Models ➡️ 论文作者:Jitesh Jain, Jianwei Yang, Humphrey Shi ➡️ 研究机构: SHI Labs…...
前端根据后端返回的excel二进制文件流进行导出下载
需求 在vue2中,后端接口返回一个文件流,前端实现excel文件流导出下载功能。 解决方案 利用axios请求后端接口,把后端返回的blob文件流转为一个临时在线url,然后利用a标签实现导出下载功能。 具体实现步骤 1、封装axios请求拦…...
代码随想录刷题|Day20(组合总数,组合总数2、分割回文串)
回溯算法 Part02 组合总数 力扣题目链接 代码随想录链接 视频讲解 题目描述: 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你…...
【NLP 64、基于LLM的垂直领域【特定领域】问答方案】
找不到生活的答案,就先找自己 —— 25.4.17 一、垂直领域问答 1.特点 ① 问答内容通常不存在于通用语料 ② 回答内容对准确性要求较高,召回要求较低(可以转人工处理) ③ 拓展性和可控性(可以根据需求,增、…...
pytest自动化中关于使用fixture是否影响用例的独立性
第一个问题:难道使用fixture 会不会影响用例独立 ✅ 简单回答: 使用 fixture ≠ 不独立。 只要你的 fixture 是每次测试都能自己运行、自己产生数据的,那么测试用例依然是“逻辑独立”的。 ✅ 怎么判断 fixture 是否影响独立性?…...
嵌入式物联网开发(二)如何创建N32G45的Keil工程并实现串口打印
如何创建N32G45的Keil工程并实现串口打印 打开Keil IDE, 点击菜单栏Project按钮,选择Create New Project,并在弹出的对话框中选择工程目录,并取一个名字,这里取名bootloader:在弹出的对话框中选择我们的对应的芯片型号: N32G452R…...
基于Canal+Spring Boot+Kafka的MySQL数据变更实时监听实战指南
前期知识背景 binlog 什么是binlog 它记录了所有的DDL和DML(除 了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL 的二进制日志是事务安全型的。一般来说开启二进制日志大概会有1%的性能损耗。 binlog分类 MySQL Bi…...
Unity入门笔记(缘更)
内容来源SiKi学院的Luna’s Fantasy 文章目录 一、基础知识1.准备2.基础知识1.层级(Layer)2.轴心点3.预制体(Prefab)4.刚体组件(Rigidbody)5.碰撞器组件(BoxCollider) 二、代码1.移动 一、基础知识 1.准备 Unity安装: https://unity.cn 2.基础知识 1.层级(Layer…...
SpringAI+DeepSeek大模型应用开发——2 大模型应用开发架构
目录 2.大模型开发 2.1 模型部署 2.1.1 云服务-开放大模型API 2.1.2 本地部署 搜索模型 运行大模型 2.2 调用大模型 接口说明 提示词角色 编辑 会话记忆问题 2.3 大模型应用开发架构 2.3.1 技术架构 纯Prompt模式 FunctionCalling RAG检索增强 Fine-tuning …...
Prometheus thanos架构
Thanos 是一个用于扩展 Prometheus 的高可用性和长期存储的解决方案。它通过整合多个 Prometheus 实例,提供了全局查询、长期存储、以及高可用性的能力。Thanos 的架构主要由以下几个核心组件组成: 1. Sidecar 功能: Sidecar 是与每个 Prom…...
嵌入式软件--stm32 DAY 1
一、STM32概述 1.ARM内核 ARM是一家英国公司。后被日本软银收购。 RISC(精简指令集计算机) 产品:ARM架构处理器,相关外围组件的电路设计方案。 怎么卖 :知识产权授权 只卖方案不卖具体产品 买了如何用 拿到ARM的方案 设计产…...
【家政平台开发(53)】解锁家政平台高可用秘籍:负载均衡与架构部署
本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析,剖析家政行业现状、挖掘用户需求与梳理功能要点,到系统设计阶段的架构选型、数据库构建,再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化,测试阶段多维度保障平台质量,…...
Kotlin整数相除精度损失roundToInt
Kotlin整数相除精度损失roundToInt import kotlin.math.roundToIntfun main() {val a 0.0fval delta 0.1ffor (i in 0..10) {val r a i * deltaprintln("float${r} toInt${r.toInt()} (0.5 toInt)${(r 0.5).toInt()} round${Math.round(r)} roundToInt${r.roundToInt…...
RPCRT4!OSF_CCONNECTION::OSF_CCONNECTION函数分析之初始化中的u.ConnSendContext----RPC源代码分析
RPCRT4!OSF_CCONNECTION::OSF_CCONNECTION函数分析之初始化中的u.ConnSendContext 第一部分: 1: kd> kc # 00 RPCRT4!OSF_CCONNECTION::OSF_CCONNECTION 01 RPCRT4!OSF_CASSOCIATION::AllocateCCall 02 RPCRT4!OSF_BINDING_HANDLE::AllocateCCall 03 RPCRT4!OSF…...