Java的ForkJoinPool:深入理解并发编程的利器
在现代软件开发中,多核处理器的普及使得并发编程成为提升应用性能的关键。Java作为一门广泛使用的编程语言,提供了丰富的并发工具,其中ForkJoinPool是Java 7引入的一个强大组件,专为处理可递归分解的任务设计。它通过分治算法和工作窃取机制,最大化利用多核处理器的计算能力,显著提升计算密集型任务的效率。
本文将全面探讨ForkJoinPool的原理、特性、使用方法以及在实际开发中的最佳实践。通过清晰的结构、深入的分析和丰富的代码示例,我们旨在帮助开发者从入门到精通,掌握这一并发编程利器。文章将涵盖以下内容:
- 并发编程简介:为什么需要并发,以及Java中的并发工具。
- ForkJoinPool概述:定义、核心思想和工作原理。
- 关键特性:工作窃取算法、公共池、并行度等。
- 使用ForkJoinPool:创建池、提交任务、处理结果。
- ForkJoinTask详解:RecursiveAction和RecursiveTask的区别与应用。
- 高级主题:异步模式、阻塞管理、监控和关闭。
- 最佳实践与常见陷阱:如何高效使用,避免错误。
- 与其他并发工具的比较:与ThreadPoolExecutor、Parallel Streams的异同。
- 结论:总结优势和适用场景。
本文将通过通俗易懂的语言和详细的代码示例,确保读者能够轻松理解并在实际项目中应用ForkJoinPool。
1. 并发编程简介
1.1 为什么需要并发编程
在单核处理器时代,程序性能主要依赖于单线程优化。然而,随着多核处理器的普及,单线程无法充分利用硬件资源,导致性能瓶颈。并发编程允许多个任务同时执行,从而提高CPU利用率、吞吐量和响应速度。例如,在处理大数据集或执行复杂计算时,并发可以显著缩短运行时间。
然而,并发编程也带来挑战:
- 线程管理复杂:手动创建和管理线程需要处理同步、死锁等问题。
- 资源开销:每个线程需要分配栈空间和操作系统资源,过多线程会导致内存压力。
- 性能瓶颈:不当的线程调度可能导致上下文切换频繁或线程争用。
Java的并发框架通过抽象线程管理,简化了开发者的工作。ExecutorService是其中的核心接口,提供了线程池管理和任务执行的功能。
1.2 ExecutorService与并发工具
ExecutorService接口抽象了线程池的管理,允许开发者提交任务而无需直接操作线程。其主要实现包括:
- ThreadPoolExecutor:通用线程池,支持自定义线程数、队列策略等,适合多种任务类型。
- ScheduledThreadPoolExecutor:支持定时和周期性任务。
- ForkJoinPool:专为分治算法设计,适合递归分解的任务。
ForkJoinPool因其独特的工作窃取算法和对递归任务的优化,成为处理计算密集型任务的理想选择。以下章节将深入探讨其原理和用法。
2. ForkJoinPool概述
2.1 定义与目的
ForkJoinPool是Java 7引入的ExecutorService实现,属于Fork/Join框架的一部分。它设计用于处理可递归分解的任务,通过分治算法将大任务拆分为小任务并行执行,最终合并结果。ForkJoinPool特别适合以下场景:
- 快速排序:递归分区数组。
- 矩阵运算:分解矩阵为小块并行计算。
- 文件处理:递归遍历目录结构。
与传统线程池不同,ForkJoinPool通过工作窃取算法动态平衡任务负载,确保所有线程高效工作。
2.2 工作原理
ForkJoinPool的工作流程可以概括为:
- 任务提交:将大任务提交到池中。
- 任务分解(Fork):任务被递归分解为小任务,放入线程的任务队列。
- 任务执行:线程从本地队列取出任务执行,空闲线程从其他线程队列偷取任务。
- 任务合并(Join):等待子任务完成,合并结果。
核心机制是工作窃取:每个线程维护一个双端队列(Deque),任务按LIFO(后进先出)顺序执行;空闲线程从其他线程队列的尾部(FIFO,先进先出)偷取任务。这种设计减少了竞争,提高了效率。
2.3 与传统线程池的区别
特性 | ForkJoinPool | ThreadPoolExecutor |
---|---|---|
任务类型 | 专为ForkJoinTask设计 | 支持任意Runnable/Callable |
调度策略 | 工作窃取算法 | FIFO或LIFO队列 |
线程管理 | 动态调整,默认等于核心数 | 可配置核心和最大线程数 |
适用场景 | 计算密集型、递归任务 | 通用,包括I/O密集型任务 |
3. 关键特性
3.1 工作窃取算法
工作窃取是ForkJoinPool的核心优势。每个线程拥有一个双端队列:
- 本地执行:线程从队列头部(LIFO)取出任务,优化缓存局部性。
- 任务偷取:空闲线程从其他线程队列尾部(FIFO)偷取任务,减少竞争。
这种机制确保任务均匀分布,避免线程闲置。例如,在处理不平衡的任务树时,工作窃取能有效平衡负载。
3.2 公共池(Common Pool)
ForkJoinPool提供静态方法commonPool()
,返回一个共享池,默认并行度为处理器核心数(Runtime.getRuntime().availableProcessors()
)。公共池适合大多数应用,优点包括:
- 资源效率:避免创建多个池。
- 简单性:无需手动配置。
但需注意:
- 争用风险:多任务竞争可能降低性能。
- 配置限制:无法自定义参数。
3.3 并行度
并行度决定池中同时运行的线程数,默认等于核心数,可通过构造器指定:
ForkJoinPool pool = new ForkJoinPool(4); // 4个线程
最大并行度为32767,超出会抛出IllegalArgumentException
。选择合适的并行度需考虑:
- 过高:增加上下文切换开销。
- 过低:无法充分利用多核。
3.4 异步模式
通过构造器设置asyncMode=true
,启用FIFO调度,适合不需等待结果的异步任务:
ForkJoinPool asyncPool = new ForkJoinPool(4, null, null, true);
默认模式(asyncMode=false
)更适合需要合并结果的任务。
3.5 动态线程管理
ForkJoinPool自动调整线程数,创建新线程以应对负载,终止空闲线程以节省资源。它还能处理任务等待(如join操作)时的线程分配,确保效率。
3.6 监控方法
ForkJoinPool提供多种监控方法:
getActiveThreadCount()
:活跃线程数。getQueuedTaskCount()
:队列任务数。getStealCount()
:偷取任务总数。toString()
:池状态字符串。
这些方法有助于调试和性能优化。
4. 使用ForkJoinPool
4.1 创建ForkJoinPool
创建方式包括:
- 公共池:
ForkJoinPool pool = ForkJoinPool.commonPool();
- 自定义池:
ForkJoinPool pool = new ForkJoinPool(4);
4.2 提交任务
支持的任务提交方法:
execute(ForkJoinTask)
:异步执行,无返回值。invoke(ForkJoinTask)
:同步执行,返回结果。submit(ForkJoinTask)
:异步执行,返回Future。invokeAll(ForkJoinTask...)
:执行多个任务,等待完成。
4.3 示例:数组总和
以下示例计算数组总和:
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class ArraySumTask extends RecursiveTask<Long> {private static final int THRESHOLD = 100;private long[] array;private int start, end;public ArraySumTask(long[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}@Overrideprotected Long compute() {if (end - start <= THRESHOLD) {long sum = 0;for (int i = start; i < end; i++) {sum += array[i];}return sum;}int mid = (start + end) / 2;ArraySumTask left = new ArraySumTask(array, start, mid);ArraySumTask right = new ArraySumTask(array, mid, end);invokeAll(left, right);return left.join() + right.join();}public static void main(String[] args) {long[] array = new long[1000];for (int i = 0; i < 1000; i++) {array[i] = i;}ForkJoinPool pool = new ForkJoinPool();ArraySumTask task = new ArraySumTask(array, 0, array.length);long result = pool.invoke(task);System.out.println("总和:" + result);}
}
4.4 示例:字符串转大写
使用RecursiveAction将字符串列表转为大写:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;public class UppercaseAction extends RecursiveAction {private static final int THRESHOLD = 10;private List<String> list;public UppercaseAction(List<String> list) {this.list = list;}@Overrideprotected void compute() {if (list.size() <= THRESHOLD) {for (int i = 0; i < list.size(); i++) {list.set(i, list.get(i).toUpperCase());}} else {int mid = list.size() / 2;List<String> left = list.subList(0, mid);List<String> right = new ArrayList<>(list.subList(mid, list.size()));invokeAll(new UppercaseAction(left), new UppercaseAction(right));}}public static void main(String[] args) {List<String> strings = new ArrayList<>();for (int i = 0; i < 20; i++) {strings.add("string" + i);}ForkJoinPool pool = new ForkJoinPool();UppercaseAction action = new UppercaseAction(strings);pool.invoke(action);System.out.println(strings);}
}
5. ForkJoinTask详解
ForkJoinTask是ForkJoinPool的任务基类,支持两种子类:
- RecursiveAction:无返回值,适合修改数据或执行操作。
- RecursiveTask:返回类型为V,适合计算结果。
5.1 RecursiveAction
示例:递归遍历目录:
import java.util.concurrent.RecursiveAction;
import java.io.File;public class DirectoryTraversal extends RecursiveAction {private File directory;public DirectoryTraversal(File directory) {this.directory = directory;}@Overrideprotected void compute() {File[] files = directory.listFiles();if (files != null) {for (File file : files) {if (file.isDirectory()) {DirectoryTraversal task = new DirectoryTraversal(file);task.fork();} else {System.out.println(file.getName());}}}}
}
5.2 RecursiveTask
示例:查找最大值:
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class MaximumFindTask extends RecursiveTask<Integer> {private static final int THRESHOLD = 100;private int[] array;private int start, end;public MaximumFindTask(int[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}@Overrideprotected Integer compute() {if (end - start <= THRESHOLD) {int max = array[start];for (int i = start + 1; i < end; i++) {if (array[i] > max) max = array[i];}return max;}int mid = (start + end) / 2;MaximumFindTask left = new MaximumFindTask(array, start, mid);MaximumFindTask right = new MaximumFindTask(array, mid, end);invokeAll(left, right);return Math.max(left.join(), right.join());}public static void main(String[] args) {int[] array = {1, 4, 2, 7, 3, 8, 5, 9, 6, 10};ForkJoinPool pool = new ForkJoinPool();MaximumFindTask task = new MaximumFindTask(array, 0, array.length);int max = pool.invoke(task);System.out.println("最大值:" + max);}
}
6. 高级主题
6.1 管理阻塞
ForkJoinTask不适合阻塞操作(如I/O)。若需阻塞,使用ManagedBlocker
:
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;public class BlockingTask extends ForkJoinTask<Void> {@Overridepublic Void getRawResult() { return null; }@Overrideprotected void setRawResult(Void value) {}@Overrideprotected boolean exec() {try {ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {@Overridepublic boolean block() throws InterruptedException {LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));return true;}@Overridepublic boolean isReleasable() { return false; }});System.out.println("任务完成");} catch (InterruptedException e) {Thread.currentThread().interrupt();}return true;}public static void main(String[] args) {ForkJoinPool pool = new ForkJoinPool();BlockingTask task = new BlockingTask();pool.invoke(task);}
}
6.2 监控
监控方法包括:
getActiveThreadCount()
:活跃线程数。getQueuedTaskCount()
:队列任务数。getStealCount()
:偷取任务数。toString()
:池状态。
6.3 关闭池
使用shutdown()
或shutdownNow()
:
ForkJoinPool pool = new ForkJoinPool();
pool.shutdown();
try {pool.awaitTermination(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {pool.shutdownNow();
}
7. 最佳实践与常见陷阱
7.1 最佳实践
- 优先使用公共池:除非需要自定义配置。
- 合理阈值:平衡任务分解开销与并行度。
- 避免阻塞:使用
ManagedBlocker
处理阻塞。 - 异常处理:重写
onException
方法捕获异常。 - 监控调优:使用监控方法优化性能。
7.2 常见陷阱
- 任务过细:过多分解增加开销。
- 任务过大:无法充分利用核心。
- I/O任务:ForkJoinPool不适合I/O密集型任务。
- 未关闭池:可能导致资源泄漏。
8. 与其他并发工具的比较
工具 | ForkJoinPool | ThreadPoolExecutor | Parallel Streams |
---|---|---|---|
任务类型 | ForkJoinTask | Runnable/Callable | Stream操作 |
调度策略 | 工作窃取 | FIFO/LIFO队列 | 基于ForkJoinPool |
适用场景 | 计算密集型、递归任务 | 通用,包括I/O任务 | 数据处理 |
配置灵活性 | 有限 | 高 | 最低 |
Parallel Streams示例:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream().reduce(0, Integer::sum);
9. 结论
ForkJoinPool是Java并发编程的强大工具,特别适合处理递归分解的计算密集型任务。其工作窃取算法和动态线程管理使其在多核环境中表现出色。通过合理设计任务和遵循最佳实践,开发者可以显著提升应用性能。
建议从简单任务开始尝试ForkJoinPool,逐步优化阈值和任务分解策略。结合监控工具和异常处理,确保应用稳定高效。随着Java生态的演进,ForkJoinPool将继续在高性能计算中发挥重要作用。
相关文章:
Java的ForkJoinPool:深入理解并发编程的利器
在现代软件开发中,多核处理器的普及使得并发编程成为提升应用性能的关键。Java作为一门广泛使用的编程语言,提供了丰富的并发工具,其中ForkJoinPool是Java 7引入的一个强大组件,专为处理可递归分解的任务设计。它通过分治算法和工…...
结合 Python 与 MySQL 构建你的 GenBI Agent_基于 MCP Server
写在前面 商业智能(BI)正在经历一场由大型语言模型(LLM)驱动的深刻变革。传统的 BI 工具通常需要用户学习复杂的界面或查询语言,而生成式商业智能 (Generative BI, GenBI) 则旨在让用户通过自然语言与数据交互,提出问题,并获得由 AI 生成的数据洞察、可视化建议甚至完整…...
道路运输安全员企业负责人考试内容与范围
道路运输企业主要负责人(安全员)考证要求 的详细说明,适用于企业法定代表人、分管安全负责人等需取得的 《道路运输企业主要负责人和安全生产管理人员安全考核合格证明》(交通运输部要求)。 考试内容与范围 1. 法律法…...
一体化安全管控平台:消防“一张图”与APP统一管理的创新模式
在科技飞速发展的当下,智慧消防已成为消防救援行业不可阻挡的发展趋势。随着城市化进程的加速,城市规模不断扩大,建筑结构愈发复杂,传统的消防管理模式逐渐暴露出诸多弊端,难以满足现代社会对消防安全的高标准要求。 智…...
利用pnpm patch给第三方库打补丁
如果在使用第三方库的时候, 发现bug, 但是等不了官方补丁, 可以使用pnpm patch给第三方库打补丁来解决, 类似 git diff, 操作如下: 在package.json所在目录的命令行执行 pnpm patch jiaminghi/data-view执行完这个命令后会生成临时文件夹供你编辑, 然后开始编辑这个临时文件夹…...
Spark-SQL(三)
一. 数据加载与保存 1. 数据加载: spark.read.load 是加载数据的通用方法。 spark.read.format("…")[.option("…")].load("…") 1)format("…"):指定加载的数据类型。 2)load("…"…...
centosu7 二进制安装mysql5.7
一、准备工作 1. 卸载原有MariaDB(如有) sudo yum remove -y mariadb-libs sudo rm -rf /var/lib/mysql 2. 安装依赖 sudo yum install -y libaio numactl openssl-devel 3. 创建MySQL用户和目录 sudo groupadd mysql sudo useradd -r -g mysql -s…...
生物信息与自动化控制1 - 传感器数据采集与PID 算法的应用
1. 生物过程自动化控制 在生物制药、发酵工程等生物过程中,可以利用生物信息学技术分析生物反应的机理和代谢网络,然后通过自动化控制系统对生物过程进行实时监测和优化控制,以提高生物产品的产量和质量。例如,在发酵过程中&…...
npm包管理工具理解
一、当前维护者:GitHub(微软旗下) 2018 年,npm 公司被 GitHub 收购; 2020 年,GitHub 被微软收购。 因此,目前 npm 公共仓库由 GitHub 团队负责运维,微软提供底层基础设施支持&#…...
Uniapp 使用Android studio进行离线打包
一.需求 开发Uniapp项目时,使用HBuilderX进行云打包,会经常遇到两个方面的问题,当天的打包的次数受到了限制和打包的时间会比较长,因此,对于离线打包其需求还是比较常见的,这篇文章记录一下对Uniapp的项目…...
mcp和API区别
MCP(Model Context Protocol,模型上下文协议)与传统API(Application Programming Interface,应用程序编程接口)在技术架构、集成方式和应用场景等方面存在显著差异,以下是主要区别的总结&#x…...
ASP.NET 中 Cache 的常规使用方法
在 ASP.NET 中,Cache 类提供了一种在服务器内存中存储数据的方法,可以显著提高应用程序性能。以下是 Cache 的常规使用方法: 1. 基本缓存操作 添加缓存项 // 最简单的添加方式 Cache["key"] "value";// 使用 Insert …...
TextIn ParseX文档解析参数使用指南(第一期)
TextIn ParseX通用文档解析作为一款适配多样化场景的PDF解析工具,在基础识别能力以上,还提供了便捷、完善的参数配置功能,便于用户根据自身需求调整,获得所需输出结果。在TextIn技术社群,我们的产品团队也经常接到关于…...
[图论]生成树 引言
生成树 引言 生成树:一个连通图的生成树是该图的一个极小连通子图。生成树中含有图中全部(设 V V V个)顶点及构成一棵树的 V − 1 V-1 V−1条边,且生成树中不应有环。最小生成树(MST):图的所有生成树中,边权之和最小的生成树。显…...
生信小白学Rust-02
基本类型 Rust 每个值都有其确切的数据类型,总的来说可以分为两类:基本类型和复合类型。 基本类型意味着它们往往是一个最小化原子类型,无法解构为其它类型(一般意义上来说),由以下组成: 数值…...
Docker Compose 中配置 Host 网络模式
在 Docker Compose 中配置 Host 网络模式时,需通过 network_mode 参数直接指定容器使用宿主机的网络栈。以下是具体配置方法及注意事项: 1. 基础配置示例 在 docker-compose.yml 文件中,为需要启用 Host 模式的服务添加 network_mode: "…...
SQL Server 2022 安装常见问题及解决方法
一、系统要求不满足 1. 硬件配置不足 SQL Server 2022 对硬件有一定要求,若内存、磁盘空间不足,安装可能失败。例如,32 位系统至少需要 1GB 内存,64 位系统至少 2GB,且安装过程需预留足够磁盘空间。 解决方法&a…...
解决 AWS RDS MySQL mysqldump 导入sql SET @@GLOBAL 权限不足问题
在使用 mysqldump 导出数据库时,导出的 SQL 文件通常会包含一些 SET 语句,例如 SET MYSQLDUMP, SET SESSION, SET GLOBAL 等,这些语句用于设置会话或全局变量以确保数据一致性和兼容性。然而,在 AWS RDS MySQL 环境中,…...
加油站小程序实战教程11会员注册
目录 1 创建API2 搭建页面布局3 绑定事件总结 上一篇我们介绍了我的页面,显示未开通界面的搭建。当用户点击开通会员时,我们给出弹窗提示用户进行手机号授权,得到手机号之后我们调用API来完成会员的注册。本篇我们介绍一下会员注册的流程。 1…...
基于stm32的手机无线充电研究
标题:基于stm32的手机无线充电研究 内容:1.摘要 随着智能手机的普及,无线充电技术成为了研究热点。本研究的目的是设计并实现基于STM32的手机无线充电系统。采用电磁感应原理,以STM32微控制器为核心控制单元,设计了发射端和接收端电路。通过…...
如何快速隔离被攻击的服务器以防止横向渗透
当发现服务器被攻击时,迅速隔离是防止攻击者横向移动的关键措施。以下是快速隔离服务器的系统化方法: 一、立即网络隔离措施 1. 物理隔离(最彻底) 直接拔掉服务器的网线(对物理服务器) 关闭服务器电源&a…...
Ngrok 内网穿透实现Django+Vue部署
目录 Ngrok 配置 注册/登录 Ngrok账号 官网ngrok | API Gateway, Kubernetes Networking Secure Tunnels 直接cmd运行 使用随机生成网址:ngrok http 端口号 使用固定域名生成网址:ngrok http --domain你的固定域名 端口号 Django 配置 1.Youre a…...
信息学奥赛一本通 1508:Easy SSSP
【题目链接】 ybt 1508:Easy SSSP 【题目考点】 1. SPFA算法 判断负环 【解题思路】 使用SPFA统计整个图中是否有负环,初始需要将所有顶点都入队。 可以假想存在一个超级源点,第0号顶点。第0号顶点到第1到第n号顶点都有权值为0的边。 &a…...
兔子桌面官方下载-兔子桌面TV版-安卓电视版官方免费下载新版
想要体验兔子桌面 TV 版带来的诸多便利,下载安装非常简单。以下为你详细介绍官方免费下载新版的步骤: 安卓电视盒子下载方法 确保电视盒子已连接网络,打开盒子自带的浏览器,访问兔子桌面官方网站。 在官网找到 TV 版下载入口&am…...
国标GB28181视频平台EasyCVR视频汇聚系统,打造别墅居民区智能监控体系
一、现状背景 随着国家经济的快速增长,生活水平逐渐提高,私人别墅在城市、乡镇和农村的普及率也在逐年增加。然而,由于别墅区业主经济条件较好,各类不法事件也日益增多,主要集中在以下几个方面: 1&#x…...
天元证券|奶粉行业结构性回暖 乳企竞速全龄化、国际化
在过去几年中,中国婴配粉市场经历了量价齐增,量减价增,量减价减的三个周期。历经多年行业深度洗牌与竞争格局重塑,2024年中国婴配粉市场回暖态势愈发清晰可辨。 日前,包括中国飞鹤、澳优、健合集团在内的多家奶粉股披露…...
JVM:对象的实例化、直接内存
一、对象的实例化 对象实例化步骤: 首先加载对象所属类的相关信息,若该类存在父类,那么要将父类的信息也加载进来,依此类推接着在堆中为对象分配内存,有两种分配方法:当堆内存空间较为规整时,…...
Qwen2.5-Omni 7B 模型部署:镜像下载、环境安装及 demo 启动指南
本文采用docker方式启动 参考:https://github.com/QwenLM/Qwen2.5-Omni 下载模型 modelscope download --model Qwen/Qwen2.5-Omni-7B --local_dir /usr/local/ai/models/Qwen2.5-Omni-7B 下载docker镜像(耗时较长,耐心等待) d…...
【DeepSeek答】如何成为一名科技领域陪同口译,阶段性学习目标是什么
问:请问我怎样能成为一名陪同口译?需要学习哪些方面?如何阶段性达成目标?我每天晚上可以抽出一个小时学习,周六日全天学习。请帮我具体规划出阶段性的学习路线,并且给出学习教材 DeepSeek答: 根…...
AN(G|C)LE as an OpenCL Compute Driver
AN{G|C}LE as an OpenCL Compute Driver References Vulkanised 2024 https://vulkan.org/events/vulkanised-2024 References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/...
在云服务器的 Linux 系统中安装 Python 的步骤(以常见发行版 Ubuntu/CentOS 为例)
一、Ubuntu/Debian 系统安装 Python 1. 更新系统包列表 sudo apt update && sudo apt upgrade -y2. 安装编译依赖 sudo apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev…...
spark-SQL核心编程课后总结
通用加载与保存方式 加载数据:Spark-SQL的 spark.read.load 是通用加载方法,借助 format 指定数据格式,如 csv 、 jdbc 、 json 等; load 用于指定数据路径; option 在 jdbc 格式时传入数据库连接参数。此外࿰…...
stm32c011f4烧写程序 could not stop Cortex-M device
stm32c011f4烧写程序 could not stop Cortex-M device 一、问题描述二、问题分析三、解决方案说明:新的问题解决办法 四、其他可能原因分析可能的原因及解决方案(一)硬件连接问题1、复位引脚(NRST)状态异常2、 JTAG/SW…...
【Web API系列】Web Shared Storage API之WorkletSharedStorage深度解析与实践指南
前言 在现代Web开发领域,数据存储与隐私保护的矛盾始终存在。传统存储方案如LocalStorage和Cookies面临着日益严格的安全限制,而跨域数据共享的需求却在持续增长。正是在这样的背景下,Web Shared Storage API应运而生,其核心组件…...
nvm切换node版本后,解决npm找不到的问题
解决方法如下 命令行查看node版本 node -v找到node版本所对应的npm版本 点击进入node版本 npm对应版本下载 点击进入npm版本 下载Windows 压缩包 下载完成后,解压,文件改名为npm 复制到你nvm对应版本的node_modules 下面 将下载的npm /bin 目录…...
【路由交换方向IE认证】BGP选路原则之Local Preference属性
文章目录 一、路由器BGP路由的处理过程控制平面和转发平面选路工具 二、BGP的选路顺序选路的前提选路顺序 三、Local Preference属性选路原则Local Preference选路方法Local Preference选路时的方向、方式设置直接更改Local Preference值使用route-map更改Local Preference值 四…...
MTK-Android12 13 屏蔽掉Viewing full screen
去掉ROOM 开机第一次提示全屏弹框 文章目录 需求参考资料修改文件实现方案 解决思路grep 源码查找信息grep 查找 grep -rn "Viewing full screen" 找string 字段grep 查找 grep -rn immersive_cling_title 布局grep 查找 grep -rn layout.immersive_mode_cling 对应的…...
Elasticsearch 查询排序报错总结
Elasticsearch 查询sort报错总结 文章目录 Elasticsearch 查询`sort`报错总结错误1、使用Es对 `sort` 进行排序字段类型的要求1.1、数值类型(如 `integer`、`long`、`float`、`double`)1.2、日期类型(如 `date`)1.3、字符串类型(如 `keyword`、`text`)1.4、布尔类型(`bo…...
Docker私有仓库页面访问实现
通过 docker run -d -p 5000:5000 --name registry registry:2 命令搭建的Docker私有仓库默认不提供网页访问界面。它是一个基于API的后端服务,主要用于镜像的存储和管理。但可以通过以下两种方式实现网页访问: 一、通过第三方Web UI工具扩展 1. 使用 D…...
TVS管与ESD保护二极管详解:原理、区别与应用选型
一、TVS管(瞬态电压抑制二极管) 1. 基本定义 TVS管(Transient Voltage Suppressor) 是一种用于抑制瞬态高压脉冲的半导体器件,通过雪崩击穿效应快速钳位电压,保护后端电路。 2. 核心特性参数 参数定义公…...
基于问题解决的Python编程教学对高中学生计算思维能力的培养研究
一、引言 1.1 研究背景与意义 在数字化时代飞速发展的当下,人工智能、大数据、云计算等新兴技术深刻地改变着人们的生活与工作方式。计算思维作为一种运用计算机科学的基础概念进行问题求解、系统设计以及人类行为理解的思维活动,已成为 21 世纪公民必…...
基于Vue Node.js的电影售票网站的设计与实现(源码+lw+部署文档+讲解),源码可白嫖!
摘要 互联网技术的成熟和普及,势必会给人们的生活方式带来不同程度的改变。越来越多的经营模式中都少不了线上运营,互联网正强力推动着社会和经济发展。国人对民族文化的自信和不同文化的包容,再加上电影行业的发展,如此繁荣吸引…...
Golang Event Bus 最佳实践:使用 NSQite 实现松耦合架构
Go Event Bus 最佳实践:使用 NSQite 实现松耦合架构 什么是 Event Bus? Event Bus(事件总线)是一种消息传递模式,它允许应用程序的不同组件通过发布/订阅机制进行通信,而不需要直接相互依赖。这种模式特别…...
XSS 跨站Cookie 盗取表单劫持网络钓鱼溯源分析项目平台框架
漏洞原理:接受输入数据,输出显示数据后解析执行 基础类型:反射 ( 非持续 ) ,存储 ( 持续 ) , DOM-BASE 拓展类型: jquery , mxss , uxss , pdfxss , flashx…...
LeetCode算法题(Go语言实现)_49
题目 给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 一、代码实现(快速选择…...
运维面试题(十四)
6.将日志从一台服务器保存到另一台服务器中的方法 1.使用 rsync 同步日志文件 2.使用 scp 手动或脚本化传输 3.配置日志服务(如 syslog 或 rsyslog )远程传输 4.编写脚本定时上传:结合 cron 定时任务和传输工具,编…...
从零开始构建 Ollama + MCP 服务器
Model Context Protocol(模型上下文协议)在过去几个月里已经霸占了大家的视野,出现了许多酷炫的集成示例。我坚信它会成为一种标准,因为它正在定义工具与代理或软件与 AI 模型之间如何集成的新方式。 我决定尝试将 Ollama 中的一…...
Oracle--了解Oracle
前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 一、Oracle简介 Oracle是甲骨文公司开发的一款关系型数据库,是一款可移植性好、使用简单、功能强大的关系型数据库。它为各行业在各类环境…...
Hadoop集群部署教程-END
Hadoop集群部署教程-END 第二十九章:总结与展望 29.1 核心内容回顾 技术体系总结: 分布式存储架构:基于HDFS的多副本机制[^6]计算框架演进:从MapReduce到Spark/Flink的生态演进资源调度优化:YARN的多租户资源隔离方案…...
面试题:谈谈你对覆盖索引的理解
覆盖索引详解 一、定义 覆盖索引(Covering Index)是指索引本身包含查询所需的所有字段数据,使得数据库引擎无需访问实际数据行即可完成查询。这种技术通过减少磁盘I/O和避免回表操作来提升查询性能:ml-citation{ref“1,5” data“cit…...