Android学习总结之线程池篇
一、线程池参数调优实战真题
真题 1:直播 APP 弹幕加载线程池设计
题目描述:直播 APP 需要实时加载弹幕数据(网络请求,IO 密集型),同时渲染弹幕视图(UI 操作需切主线程),现有线程池导致弹幕卡顿,如何优化?
解题思路:
- 参数调整:
corePoolSize
:对于 IO 密集型任务,设为2 * CPU核心数
,例如 8 核设备则corePoolSize = 16
。maximumPoolSize
:适当增大到3 * CPU核心数
(即 24),以应对高并发场景。workQueue
:使用有界队列ArrayBlockingQueue(100)
,防止内存溢出。keepAliveTime
:设为60秒
,允许非核心线程存活更久。
- 任务拆分:
- 网络请求任务提交至线程池。
- 通过
Handler
将渲染任务切换到主线程。
int cpuCores = Runtime.getRuntime().availableProcessors();
// 创建线程池
ExecutorService executor = new ThreadPoolExecutor(2 * cpuCores, // 核心线程数,针对IO密集型任务设置为2 * CPU核心数3 * cpuCores, // 最大线程数,增大以应对高并发60L, // 非核心线程空闲时的存活时间TimeUnit.SECONDS, // 存活时间单位为秒new ArrayBlockingQueue<>(100), // 有界队列,容量为100new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略,任务被调用线程执行
);executor.submit(() -> {// 网络请求获取弹幕数据List<DanmuData> data = networkRequest(); // 通过Handler切换到主线程渲染弹幕new Handler(Looper.getMainLooper()).post(() -> { renderDanmu(data);});
});
回答话术:
“针对弹幕加载的 IO 密集型任务,我会从三个层面优化。首先是 线程池参数调整:
corePoolSize
设置为2 * CPU核心数
(如 8 核设备设为 16),因为 IO 任务等待时线程不占用 CPU,更多核心线程能提升并发效率;maximumPoolSize
扩展到3 * CPU核心数
(即 24),应对弹幕突发高流量;- 使用
ArrayBlockingQueue(100)
限制任务队列长度,防止内存溢出; keepAliveTime
设为 60 秒,允许非核心线程存活,减少频繁创建销毁开销。
其次, 任务拆分:网络请求提交到线程池异步执行,通过Handler
切换到主线程渲染弹幕,避免阻塞 UI。
最后, 拒绝策略 选用CallerRunsPolicy
,将被拒绝的任务回退到调用线程(通常是主线程)。这样在高并发时,若主线程空闲可临时处理任务,同时提示开发者线程池已满载,需进一步优化参数或任务分配。”
面试追问:
- 问:为什么使用
CallerRunsPolicy
拒绝策略? - 答:该策略将被拒绝的任务交给调用者线程(通常是主线程)执行,避免任务丢弃。在弹幕高并发场景下,主线程空闲时可临时处理部分任务,同时提醒开发者线程池已满载,需优化参数或任务分配。
真题 2:图片编辑 APP 线程池优化
题目描述:图片编辑 APP 在批量处理图片时(解码、裁剪、压缩,均为 CPU 密集型),出现手机发热严重且处理速度慢的问题,如何优化?
优化方案:
- 参数调整:
corePoolSize
:设为CPU核心数 + 1
(如 9)。maximumPoolSize
:与核心线程数保持一致(9),避免过多线程上下文切换。keepAliveTime
:设为0
,快速回收空闲线程。
- 性能监控:
- 使用
StrictMode
监控线程池使用情况。 - 分析 CPU 使用率,动态调整任务数量。
- 使用
int cpuCores = Runtime.getRuntime().availableProcessors();
// 创建线程池
ExecutorService executor = new ThreadPoolExecutor(cpuCores + 1, // 核心线程数,针对CPU密集型任务设置为CPU核心数 + 1cpuCores + 1, // 最大线程数,与核心线程数相同0L, // 非核心线程空闲时的存活时间设为0TimeUnit.MILLISECONDS, // 存活时间单位为毫秒new ArrayBlockingQueue<>(50), // 有界队列,容量为50new ThreadPoolExecutor.DiscardOldestPolicy() // 拒绝策略,丢弃队列中最老的任务
);
“对于 CPU 密集型的图片处理任务,优化需兼顾效率和资源消耗。
首先调整 线程池参数:
corePoolSize
设为CPU核心数 + 1
(如 8 核设备设为 9),充分利用 CPU 资源且减少上下文切换;maximumPoolSize
与核心线程数保持一致,避免创建多余线程加剧 CPU 负载;keepAliveTime
设为 0,让非核心线程立即回收,释放资源。
其次, 性能监控 必不可少:通过StrictMode
监控线程池使用,例如检测耗时任务或线程泄漏;结合 CPU 使用率动态调整任务数量,比如当 CPU 负载过高时,暂停部分任务或降低并发量。
最后, 拒绝策略 采用DiscardOldestPolicy
,丢弃队列中等待最久的任务,保证新提交的紧急任务优先执行,避免任务堆积。”
二、任务依赖与同步实战真题
真题 3:多任务顺序执行
题目描述:在文件上传功能中,需要依次完成文件压缩、加密、上传三个步骤,如何确保任务按顺序执行?
解决方案:使用 CountDownLatch
来实现任务间的同步。
// 创建CountDownLatch,初始计数值为1
CountDownLatch latch1 = new CountDownLatch(1);
// 创建另一个CountDownLatch,初始计数值为1
CountDownLatch latch2 = new CountDownLatch(1); // 提交压缩任务到线程池
executor.submit(() -> { compressFile(); // 执行文件压缩操作latch1.countDown(); // 压缩任务完成,计数值减1
});// 提交加密任务到线程池
executor.submit(() -> { try {latch1.await(); // 等待压缩任务完成(计数值变为0)encryptFile(); // 执行文件加密操作latch2.countDown(); // 加密任务完成,计数值减1} catch (InterruptedException e) {e.printStackTrace();}
});// 提交上传任务到线程池
executor.submit(() -> { try {latch2.await(); // 等待加密任务完成(计数值变为0)uploadFile(); // 执行文件上传操作} catch (InterruptedException e) {e.printStackTrace();}
});
回答话术:
“我会使用 CountDownLatch
实现任务同步。首先创建两个 CountDownLatch
,初始计数值都为 1,分别控制压缩→加密、加密→上传的依赖关系。
提交任务时,压缩任务完成后调用 latch1.countDown()
释放信号;加密任务通过 latch1.await()
等待压缩完成,完成后再释放 latch2
;最后上传任务等待 latch2
信号。这样通过计数器的增减,强制任务按顺序执行。
若任务失败,可在每个任务中捕获异常并记录,后续通过 CyclicBarrier
或自定义状态机实现重试逻辑。例如,若加密失败,回滚压缩结果并重新执行压缩和加密,确保流程可靠性。”
面试追问:
- 问:如果中间某个任务失败怎么办?
- 答:可以在每个任务中捕获异常,记录失败信息。使用
CyclicBarrier
或自定义状态机来管理任务重试逻辑,确保整体流程的可靠性。
真题 4:任务优先级调度
题目描述:APP 中有高优先级的用户登录任务和低优先级的日志上报任务,如何确保高优先级任务优先执行?
解决方案:使用 PriorityBlockingQueue
来实现任务优先级调度。
// 定义一个实现Runnable和Comparable接口的任务类
class PrioritizedTask implements Runnable, Comparable<PrioritizedTask> { private final int priority; // 任务优先级private final Runnable task; // 具体任务public PrioritizedTask(int priority, Runnable task) {this.priority = priority;this.task = task;}@Overridepublic void run() {task.run(); // 执行具体任务}@Overridepublic int compareTo(PrioritizedTask other) {return Integer.compare(other.priority, this.priority); // 比较任务优先级,倒序排列,高优先级在前}
}// 创建线程池
ExecutorService executor = new ThreadPoolExecutor(5, // 核心线程数10, // 最大线程数30L, // 非核心线程空闲时的存活时间TimeUnit.SECONDS, // 存活时间单位为秒new PriorityBlockingQueue<>() // 优先级队列
);// 提交高优先级的用户登录任务
executor.submit(new PrioritizedTask(1, () -> login()));
// 提交低优先级的日志上报任务
executor.submit(new PrioritizedTask(2, () -> uploadLog()));
回答话术:
“使用 PriorityBlockingQueue
作为线程池的任务队列即可实现。自定义 PrioritizedTask
类,实现 Comparable
接口并重写 compareTo
方法,按优先级倒序排列(高优先级在前)。线程池从队列中获取任务时,始终优先执行优先级高的任务。
相比其他方案,PriorityBlockingQueue
更灵活:它基于堆结构实现,插入和获取任务的时间复杂度为 O (log n),效率较高;同时支持动态调整任务优先级。例如,若有新的高优先级登录任务加入,能立即插队执行,而低优先级的日志上报任务会暂停等待,确保核心业务的响应速度。”
三、线程池与 Android 生命周期管理
真题 5:Activity 中的线程池内存泄漏
题目描述:在 Activity 中使用线程池执行网络请求,旋转屏幕后内存占用持续上升,如何解决?
解决方案:
- 正确关闭线程池:在
Activity
的onDestroy
方法中调用executor.shutdown()
优雅关闭线程池,如需立即关闭可调用executor.shutdownNow()
。 - 使用弱引用:避免
Activity
被任务强引用导致无法回收。
public class MainActivity extends AppCompatActivity {private ExecutorService executor;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 创建固定大小的线程池executor = Executors.newFixedThreadPool(5); }@Overrideprotected void onDestroy() {super.onDestroy();executor.shutdown(); // 优雅关闭线程池// 如需立即关闭线程池,可使用executor.shutdownNow();}
}class MyTask implements Runnable {private WeakReference<Activity> activityRef; // 使用弱引用持有Activitypublic MyTask(Activity activity) {activityRef = new WeakReference<>(activity);}@Overridepublic void run() {Activity activity = activityRef.get();if (activity != null) {// 任务逻辑}}
}
回答话术:
“内存泄漏主要因线程池任务持有 Activity 强引用,或线程池未正确关闭。
首先,在 Activity
的 onDestroy
方法中调用 executor.shutdown()
优雅关闭线程池,它会等待已提交任务执行完毕后释放资源;若需立即中断任务,可使用 executor.shutdownNow()
。
其次,避免任务强引用 Activity:将任务类中的 Activity 引用改为 WeakReference
,确保 Activity 被销毁时,任务不再阻止其回收。
最后,建议将线程池与 ViewModel
或 Service
绑定,而非直接关联 Activity。例如,使用 ViewModel
管理长期运行的任务,其生命周期与 Activity 分离,能有效防止因配置变更(如旋转屏幕)导致的内存泄漏问题。”
四、WorkManager 替代方案场景
真题 6:后台任务调度
题目描述:APP 需要在设备充电且 Wi-Fi 连接时,自动备份数据到云端,如何实现?
解决方案:使用 WorkManager
结合 Constraints
来实现后台任务调度。
// 构建任务约束条件
Constraints constraints = new Constraints.Builder() .setRequiresCharging(true) // 设置任务需要设备充电.setRequiredNetworkType(NetworkType.UNMETERED) // 设置任务需要连接非计量网络(如Wi-Fi).build();// 创建一次性工作请求,指定工作类和约束条件
OneTimeWorkRequest backupWorkRequest = new OneTimeWorkRequest.Builder(BackupWorker.class) .setConstraints(constraints).build();// 将工作请求加入WorkManager队列
WorkManager.getInstance(context).enqueue(backupWorkRequest);
回答话术:
“使用 WorkManager
结合 Constraints
能轻松实现。通过 Constraints.Builder
设置条件:setRequiresCharging(true)
确保设备充电,setRequiredNetworkType(NetworkType.UNMETERED)
限制为 Wi-Fi 网络。然后创建 OneTimeWorkRequest
,将备份任务类和约束条件传入,最后加入 WorkManager 队列。
WorkManager 相比 ThreadPoolExecutor
有显著优势:它支持任务重试、延迟执行、系统级调度,且与 Android 生命周期深度集成(如设备重启后任务自动恢复)。而 ThreadPoolExecutor
更专注于任务并发执行,需开发者手动处理调度逻辑和资源管理。因此,对于这种有条件触发、需长期可靠运行的后台任务,WorkManager 是更优选择。”
面试追问:
- 问:WorkManager 与 ThreadPoolExecutor 的区别?
- 答:WorkManager 是 Android 提供的高级任务调度框架,支持任务重试、延迟执行、约束条件等,与系统生命周期紧密集成;而 ThreadPoolExecutor 更专注于任务的并发执行,需要开发者手动处理任务调度和资源管理。
额外具体场景设计:
一、如何设计线程池让 100 个任务最快完成?
1. 核心考点:线程池参数调优与 Android 场景适配
Android 面试中,线程池设计需结合设备 CPU 核心数、任务类型(CPU 密集型 / IO 密集型)以及内存管理要求,避免 OOM 和资源浪费。
关键参数设计:
- 核心线程数(corePoolSize):
- CPU 密集型任务:设为
CPU 核心数 + 1
(充分利用 CPU,避免线程上下文切换损耗),可通过Runtime.getRuntime().availableProcessors()
获取核心数。 - IO 密集型任务:设为
2 * CPU 核心数
(因 IO 等待时线程不占用 CPU,更多线程可提高并发效率)。
- CPU 密集型任务:设为
- 最大线程数(maximumPoolSize):
- 对于 CPU 密集型,通常与核心线程数一致(避免无意义的线程创建);
- 对于 IO 密集型,可适当增大,但需结合任务队列容量避免内存溢出(Android 中建议使用有界队列
ArrayBlockingQueue
,而非无界队列LinkedBlockingQueue
,防止内存暴涨)。
- 任务队列(workQueue):
- 有界队列(如
ArrayBlockingQueue
):更安全,可控制并发量,避免 OOM(Android 内存受限,无界队列可能导致后台任务堆积)。 - 优先级队列(
PriorityBlockingQueue
):若任务有优先级差异,可优先执行高优先级任务。
- 有界队列(如
- 线程存活时间(keepAliveTime):
- 非核心线程空闲时的存活时间,IO 密集型任务可设稍长(如 30s),CPU 密集型可设 0(快速回收空闲线程)。
Android 禁用默认线程池(高频考点):
避免使用 Executors.newFixedThreadPool()
(无界队列导致 OOM)或 newCachedThreadPool()
(最大线程数无限),必须手动创建 ThreadPoolExecutor
,示例:
int cpuCores = Runtime.getRuntime().availableProcessors();
ExecutorService executor = new ThreadPoolExecutor(cpuCores + 1, // corePoolSize(CPU 密集型)2 * cpuCores, // maximumPoolSize(IO 密集型可增大)30L, TimeUnit.SECONDS,// keepAliveTimenew ArrayBlockingQueue<>(100), // 有界队列,容量根据任务量调整new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:任务被调用线程执行,避免丢弃
);
性能优化点:
- 任务轻量化: 避免在任务中执行耗时 UI 操作(需通过
Handler
/runOnUiThread
切换主线程)。 - 复用线程: 线程池复用线程避免频繁创建销毁开销,比
new Thread()
更高效。
二、如何确保前 99 个任务完成后再执行第 100 个任务?
1. 核心考点:同步机制选择(CountDownLatch 或 Future)
Android 面试中,需区分 任务依赖关系 和 线程间同步,常用方案:
方案一:CountDownLatch(最简洁方案)
- 原理:通过计数器(初始值 99)阻塞第 100 个任务,前 99 个任务完成时调用
countDown()
,计数器归零后第 100 个任务继续执行。 - Android 注意点:
- 第 100 个任务需在后台线程执行
latch.await()
,避免阻塞主线程(否则触发 ANR)。 - 任务中避免持有 Activity 强引用,防止内存泄漏(可使用弱引用或静态内部类)。
- 第 100 个任务需在后台线程执行
- 代码示例:
// 初始化 CountDownLatch(计数器 99)
private final CountDownLatch latch = new CountDownLatch(99);// 提交前 99 个任务
for (int i = 0; i < 99; i++) {executor.submit(() -> {// 执行任务...latch.countDown(); // 任务完成,计数器减一});
}// 提交第 100 个任务(依赖前 99 个)
executor.submit(() -> {try {latch.await(); // 阻塞直到计数器归零// 执行第 100 个任务...} catch (InterruptedException e) {Thread.currentThread().interrupt(); // 恢复中断状态}
});
方案二:Future 批量获取结果(适合任务有返回值场景)
- 原理:将前 99 个任务的
Future
存入列表,通过Future.allOf()
等待所有任务完成,再执行第 100 个任务。 - 优势:可处理任务返回值,支持异常处理(如
Future.get()
抛ExecutionException
)。 - 代码示例:
List<Future<?>> futures = new ArrayList<>(99);
for (int i = 0; i < 99; i++) {futures.add(executor.submit(() -> { /* 任务逻辑 */ }));
}// 提交第 100 个任务,等待前 99 个完成
executor.submit(() -> {try {Future.allOf(futures.toArray(new Future[0])).get(); // 阻塞直到所有完成// 执行第 100 个任务...} catch (InterruptedException | ExecutionException e) {// 处理异常}
});
方案对比(面试官可能追问):
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
CountDownLatch | 轻量、无返回值需求 | 仅支持单向等待 | 纯任务依赖场景 |
Future.allOf | 支持返回值、异常处理 | 代码稍复杂 | 任务有结果校验场景 |
三、Android 面试加分项(必答点)
-
线程池生命周期管理:
- 在 Activity/Fragment 的
onDestroy()
中调用executor.shutdown()
,避免后台线程持有上下文导致内存泄漏。 - 若需立即中断任务,调用
shutdownNow()
,并处理InterruptedException
。
- 在 Activity/Fragment 的
-
避免 ANR:
- 所有耗时任务(包括
latch.await()
/Future.get()
)必须在后台线程执行,UI 操作通过Handler
切换回主线程。
- 所有耗时任务(包括
-
替代方案(高级考点):
- 若任务需与 Android 生命周期绑定,可使用
WorkManager
(适合后台任务调度,支持延迟、重试、约束条件)。 - 对于轻量任务,可使用
ExecutorService
+HandlerThread
(自定义线程消息循环)。
- 若任务需与 Android 生命周期绑定,可使用
相关文章:
Android学习总结之线程池篇
一、线程池参数调优实战真题 真题 1:直播 APP 弹幕加载线程池设计 题目描述:直播 APP 需要实时加载弹幕数据(网络请求,IO 密集型),同时渲染弹幕视图(UI 操作需切主线程)࿰…...
03.Golang 切片(slice)源码分析(二、append实现)
Golang 切片(slice)源码分析(二、append实现) 前言: Golang 切片(slice)源码分析(一、定义与基础操作实现) 在前面的文章我们介绍了,切片的结构体与创建\扩容…...
Python实例题:pygame开发打飞机游戏
目录 Python实例题 题目 pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本 代码解释 初始化部分: 游戏主循环: 退出部分: 运行思路 注意事项 Python实例题 题目 pygame开发打飞机游戏 pygame-aircraft-game使用 Pygame 开发…...
MySQL创建了一个索引表,如何来验证这个索引表是否使用了呢?
MySQL创建了一个索引表,如何来验证这个索引表是否使用了呢? 1. 使用 EXPLAIN 分析查询执行计划 在 SQL 查询前添加 EXPLAIN 关键字,查看 MySQL 优化器是否选择了你的索引。 示例: EXPLAIN SELECT * FROM db关键输出字段: typ…...
Go语言多线程爬虫与代理IP反爬
有个朋友想用Go语言编写一个多线程爬虫,并且使用代理IP来应对反爬措施。多线程在Go中通常是通过goroutine实现的,所以应该使用goroutine来并发处理多个网页的抓取。然后,代理IP的话,可能需要一个代理池,从中随机选择代…...
Linux文件编程:操作流程与内核机制
在 Linux 操作系统中,一切皆文件,这意味着从硬盘上的数据文件、设备驱动、到管道、套接字等都以文件的形式存在。Linux 的文件系统将这些不同类型的文件统一抽象成文件对象,允许程序通过文件描述符来访问它们。 一、核心概念解析 文件描述符…...
用短说社区搭建的沉浸式生活方式分享平台
你是否想打造一个融合小红书式种草基因与论坛深度互动的全新社区?本文依托短说社区论坛系统的社区功能规划,一起来规划,如何搭建一个集内容分享、社交互动、消费决策于一体的沉浸式生活社区。 短说社区的界面样式支持普通资讯列表或瀑布流列…...
【ASR学习笔记】:语音识别领域基本术语
一、基础术语 ASR (Automatic Speech Recognition) 自动语音识别,把语音信号转换成文本的技术。 VAD (Voice Activity Detection) 语音活动检测,判断一段音频里哪里是说话,哪里是静音或噪音。 Acoustic Model(声学模型࿰…...
2025年best好用的3dsmax插件和脚本
copitor 可以从一个3dsmax场景里将物体直接复制到另一个场景中 Move to surface 这个插件可以将一些物体放到一个平面上 instancer 实体器,举例:场景中有若干独立的光源,不是实体对象,我们可以使用instancer将他变成实体。 paste …...
电厂除灰系统优化:时序数据库如何降低粉尘排放
在环保要求日益严苛的当下,电厂作为能源生产的重要主体,其除灰系统的运行效率与粉尘排放控制效果紧密相关。传统除灰系统在数据处理和排放控制方面存在一定局限性,而时序数据库凭借对时间序列数据的高效存储、处理和分析能力,为电…...
upload-labs通关笔记-第2关 文件上传之MIME绕过
目录 一、MIME字段 1. MIME 类型的作用 2. 常见的 MIME 类型 二、实验准备 1.构造脚本 2.打开靶场 3.源码分析 三、修改MIME字段渗透法 1.选择shell脚本 2.bp开启拦截 3.上传脚本bp拦包 4.bp改包 5.获取脚本地址 6.获取木马URL 7.hackbar渗透 8.蚁剑渗透 本文通…...
未来技术展望:光子量子计算集成与连续变量可视化
光子量子计算作为量子计算的重要分支,凭借其独特的光子传输优势和连续变量编码方式,正在量子计算领域掀起新的技术革命。以Xanadu公司的Borealis光量子处理器为代表,连续变量量子计算的可视化技术将面临全新的挑战与机遇。以下从技术适配、可视化方法及工具开发三个维度展开…...
vite项目使用i18n-ally未读取到文件
前言 在使用 Vue CLI 创建的Vue 3项目中,语言文件(src/lang/zh.js和en.js)正常加载。 .vscode/settings.json如下:i18n-ally.enabledParsers中增加了js {"i18n-ally.localesPaths": ["src/i18n","src/…...
yarn workspace使用指南
作用 Yarn workspace 是 Yarn 包管理工具中的一个功能,主要用于管理多包项目(monorepo)。它的主要作用如下: 支持多包结构:允许在一个仓库中管理多个独立的包或项目。项目间依赖管理:方便地在不同包之间添…...
Spring Boot 参数验证
一、依赖配置 首先确保在 pom.xml 中添加了以下依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency> 这个依赖包含了 Hibernate Valida…...
Electron学习大纲
Electron 实际工作学习大纲路线,结合技术原理、实战开发与工程化最佳实践,分为 5 大核心阶段,每个阶段包含关键知识点和实践目标,帮助快速掌握桌面应用开发能力: 阶段一:Electron 基础与环境搭建(1-2周) 核心概念与架构Electron 组成: 主进程(Main Process):控制应…...
Linux 系统中设置开机启动脚本
Linux 系统中设置开机启动脚本有多种方法,适用于不同的场景和需求。以下是几种最常用且详细的方法: 核心理念: 无论哪种方法,核心都是让系统在启动过程中的某个阶段执行你的脚本。 1. 使用 systemd (推荐,现代 Linux 发行版的标准) systemd 是目前大多数主流 Linux 发行…...
如何解决Deepseek服务器繁忙的问题?
在现如今互联网技术飞速发展的时代,AI技术也逐渐开始兴起,Deepseek作为一款强大的AI工具,可以帮助各个行业的用户高效的处理复杂任务,但是,用户在使用这一工具的过程中,可能会遇到服务器繁忙的问题…...
四、STM32 HAL库API完全指南:从功能分类到实战示例
STM32 HAL库API完全指南:从功能分类到实战示例 一、HAL库API的总体架构 STM32 HAL库(Hardware Abstraction Layer)作为STMicroelectronics推出的统一驱动框架,提供了覆盖所有STM32外设的标准化API。HAL库的API设计遵循严格的分层…...
集成学习——Bagging,Boosting
一.什么是集成学习 集成学习的基本思想是通过结合多个基学习器的预测结果,来提高模型的泛化能力和稳定性。这些基学习器可以是相同类型的算法,也可以是不同类型的算法。 当基学习器之间具有一定的差异性时,它们在面对不同的样本子集或特征子…...
如何有效追踪需求的实现情况
有效追踪需求实现情况,需要清晰的需求定义、高效的需求跟踪工具、持续的沟通反馈机制,其中高效的需求跟踪工具尤为关键。 使用需求跟踪工具能确保需求实现进度可视化、提高团队协作效率,并帮助识别和管理潜在风险。例如,使用专业的…...
网页Web端无人机直播RTSP视频流,无需服务器转码,延迟300毫秒
随着无人机技术的飞速发展,全球无人机直播应用市场也快速扩张,从农业植保巡检到应急救援指挥,从大型活动直播到智慧城市安防,实时视频传输已成为刚需。预计到2025年,全球将有超过1000万架商用无人机搭载直播功能&#…...
基于SpringBoot的蜗牛兼职网设计与实现|源码+数据库+开发说明文档
一、项目简介 蜗牛兼职网是一个集职位信息发布、用户申请、企业管理、后台运维于一体的校园类兼职招聘平台,使用 SpringBoot 作为后端核心框架,搭配 Layui Bootstrap 实现前端页面开发,前后端结合,功能齐全。 系统共分为 三种角…...
kafka消费组
Kafka【二】关于消费者组(Consumer Group)、分区(partition)和副本(replica)的理解_consumergroup-CSDN博客 定义: 消费者组是一组可以协同工作的消费者实例的集合。 每个消费者都属于一个特定…...
每日一题洛谷P8662 [蓝桥杯 2018 省 AB] 全球变暖c++
P8662 [蓝桥杯 2018 省 AB] 全球变暖 - 洛谷 (luogu.com.cn) DFS #include<iostream> using namespace std; char a[1001][1001]; bool s[1001][1001]; int res 0; int n; bool flag true; int dx[4] { -1,0,1,0 }; int dy[4] { 0,-1,0,1 }; void dfs(int x, int y)…...
2025年Energy SCI1区TOP,改进雪消融优化算法ISAO+电池健康状态估计,深度解析+性能实测
目录 1.摘要2.雪消融优化算SAO原理3.改进策略4.结果展示5.参考文献6.代码获取7.读者交流 1.摘要 锂离子电池(LIBs)的健康状态(SOH)估计对于电池健康管理系统至关重要,为了准确估计LIBs的健康状态,本文提出…...
docker使用过程中遇到概念问题
容器和虚拟机的区别 容器共享主机内核;虚拟机占用主机内核硬件容器的启动速度是秒级别;虚拟机的启动速度是分钟级别容器资源占用低,性能接近原生;虚拟机资源占用高,性能有一定的损耗容器是进程级别的隔离;…...
leetcode-hot-100(双指针)
1. 移动零 题目链接:移动 0 题目描述:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 解答 类似于签到题&#x…...
力扣HOT100之二叉树:101. 对称二叉树
这道题我本来想着挑战一下自己,尝试着用迭代的方法来做,然后就是用层序遍历,将每一层的元素收集到一个临时的一维向量中,然后再逐层判断每一层是否都是轴对称的,一旦发现某一层不是轴对称的,就直接return f…...
深入解读tcpdump:原理、数据结构与操作手册
一、tcpdump 核心原理 tcpdump 是基于 libpcap 库实现的网络数据包捕获与分析工具,其工作原理可分解为以下层次: 数据包捕获机制 底层依赖:通过操作系统的 数据链路层接口(如 Linux 的 PF_PACKET 套接字或 AF_PACKET 类型&#x…...
HTML5 中实现盒子水平垂直居中的方法
在 HTML5 中,有几种方法可以让一个定位的盒子在父容器中水平垂直居中。以下是几种常用的方法: 使用 Flexbox 布局 <div class"parent"><div class"child">居中内容</div> </div><style>.parent {di…...
个人博客系统测试报告
目录 1 项目背景 2 项目功能 3 项目测试 3.1 测试用例 3.2 登录页面测试 3.3 博客列表页面测试 3.4 博客详情页面测试 3.5 自动化测试 3.5.1 Utils类 3.5.2 登录测试页面类 3.5.3 博客列表页测试类 3.5.4 博客详情页测试类 3.5.5 博客修改页测试类 3.5.6 未登录…...
适配WIN7的最高版本Chrome谷歌浏览器109版本下载
本仓库提供了一个适用于Windows 操作系统的谷歌浏览器109版本的离线安装包。 点击下面链接下载 WIN7的最高版本Chrome谷歌浏览器109版本下载...
从规划到完善,原型标注图全流程设计
一、原型标注图:设计到开发的精准翻译器 1. 设计意图的精准传递 消除模糊性:将设计师的视觉、交互逻辑转化为可量化的数据(尺寸、颜色、动效参数),避免开发“凭感觉还原”。 统一理解标准:通过标注建立团…...
极狐GitLab 通用软件包存储库功能介绍
极狐GitLab 是 GitLab 在中国的发行版,关于中文参考文档和资料有: 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 极狐GitLab 通用软件包存储库 (BASIC ALL) 在项目的软件包库中发布通用文件,如发布二进制文件。然后,…...
系统架构-嵌入式系统架构
原理与特征 嵌入式系统的典型架构可概括为两种模式,即层次化模式架构和递归模式架构 层次化模式架构,位于高层的抽象概念与低层的更加具体的概念之间存在着依赖关系,封闭型层次架构指的是,高层的对象只能调用同一层或下一层对象…...
hive两个表不同数据类型字段关联引发的数据倾斜
不同数据类型引发的Hive数据倾斜解决方案 #### 一、原因分析 当两个表的关联字段存在数据类型不一致时(如int vs string、bigint vs decimal),Hive会触发隐式类型转换引发以下问题: Key值的精度损失:若关联字…...
制作一款打飞机游戏45:简单攻击
粒子系统修复 首先,我们要加载cow(可能是某个项目或资源),然后直接处理粒子系统。你们看到在粒子系统中,我们仍然有X滚动。这现在已经没什么意义了,因为我们正在使用一个奇怪的新系统。所以我们实际上不再…...
《Vuejs设计与实现》第 5 章(非原始值响应式方案) 中
目录 5.4 合理触发响应 5.5 浅响应与深响应 5.6 只读和浅只读 5.4 合理触发响应 为了合理触发响应,我们需要处理一些问题。 首先,当值没有变化时,我们不应该触发响应: const obj = { foo: 1 } const p = new Proxy(obj, { /* ... */ })effect(() => {console.log(p…...
深入理解 Webpack 核心机制与编译流程
🤖 作者简介:水煮白菜王,一位前端劝退师 👻 👀 文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧和知识归纳总结✍。 感谢支持💕💕&#…...
okhttp3.Interceptor简介-笔记
1. Interceptor 简介 okhttp3.Interceptor 是 OkHttp 提供的一个核心接口,用于拦截 HTTP 请求和响应,允许开发者在请求发送前和响应接收后插入自定义逻辑。它在构建灵活、可扩展的网络请求逻辑中扮演着重要角色。常见的用途包括: 添加请求头…...
交易流水表的分库分表设计
交易流水表的分库分表设计需要结合业务特点、数据增长趋势和查询模式,以下是常见的分库分表策略及实施建议: 一、分库分表核心目标 解决性能瓶颈:应对高并发写入和查询压力。数据均衡分布:避免单库/单表数据倾斜。简化运维&#…...
《AI大模型应知应会100篇》第59篇:Flowise:无代码搭建大模型应用
第59篇:Flowise:无代码搭建大模型应用 摘要:本文将详细探讨 Flowise 无代码平台的核心特性、使用方法和最佳实践,提供从安装到部署的全流程指南,帮助开发者和非技术用户快速构建复杂的大模型应用。文章结合实战案例与配…...
开发环境(Development Environment)
在软件开发与部署过程中,通常会划分 开发环境(Development)、测试环境(Testing)、生产环境(Production) 这三个核心环境,以确保代码在不同阶段的质量和稳定性。以下是它们的详细介绍…...
MySQL的sql_mode详解:从优雅草分发平台故障谈数据库模式配置-优雅草卓伊凡
MySQL的sql_mode详解:从优雅草分发平台故障谈数据库模式配置-优雅草卓伊凡 引言:优雅草分发平台的故障与解决 近日,优雅草分发平台(youyacaocn)在运行过程中遭遇了一次数据库访问故障。在排查过程中,技术…...
PyCharm 快捷键指南
PyCharm 快捷键指南 常用编辑快捷键 代码完成:Ctrl Space 提供基本的代码完成选项(类、方法、属性)导入类:Ctrl Alt Space 快速导入所需类语句完成:Ctrl Shift Enter 自动结束代码(如添加分号&#…...
【数据结构】map_set前传:二叉搜索树(C++)
目录 二叉搜索树K模型的模拟实现 二叉搜索树的结构: Insert()插入: InOrder()中序遍历: Find()查找: Erase()删除: 参考代码: 二叉搜索树K/V模型的模拟实现: K/V模型的简单应用举例&…...
ZYNQ处理器在发热后功耗增加的原因分析及解决方案
Zynq处理器(结合ARM Cortex-A系列CPU和FPGA可编程逻辑)在发热后功耗增大的现象,通常由以下原因导致。以下是系统性分析及解决方案: 1. 根本原因分析 现象物理机制漏电流(Leakage Current)增加温度升高导致…...
Vue学习百日计划-Deepseek版
阶段1:基础夯实(Day 1-30) 目标:掌握HTML/CSS/JavaScript基础,理解Vue核心概念和基础语法。 每日学习内容(2小时): HTML/CSS(Day 1-10) 学习HTML标签语义化…...
DeepSeek-R1-Distill-Qwen-1.5B代表什么含义?
DeepSeek‑R1‑Distill‑Qwen‑1.5B 完整释义与合规须知 一句话先行 这是 DeepSeek‑AI 把自家 R1 大模型 的知识,通过蒸馏压缩进一套 Qwen‑1.5B 架构 的轻量学生网络,并以宽松开源许可证发布的模型权重。 1 | 名字逐段拆解 片段意义备注DeepSee…...