JVM生产环境问题定位与解决实战(三):揭秘Java飞行记录器(JFR)的强大功能
提到飞行记录器,或许你的脑海中并未立刻浮现出清晰的画面,但一说起“黑匣子”,想必大多数人都能恍然大悟,知晓其重要性及用途。在航空领域,黑匣子作为不可或缺的设备,默默记录着飞行过程中的每一项关键数据,从飞行高度、速度到机舱内的对话,无一遗漏。一旦飞机发生事故,这些珍贵的数据便成为调查人员还原事件真相、精准定位事故原因的宝贵线索。
同样地,在软件开发的世界里,也有这样一个“黑匣子”般的存在——Java飞行记录器(Java Flight Recorder,简称JFR)。它借鉴了航空黑匣子的设计理念,却应用于一个截然不同的领域:Java应用程序的性能分析与故障排查。
一、 背景与概述
1.1 JFR 简介
Java Flight Recorder (JFR) 是 Oracle JDK 内置的性能分析工具,用于监控 JVM 和 Java 应用程序的运行时行为。其特点包括:
- 低开销:生产环境中通常仅产生
1%左右的性能损耗 - 实时监控:可记录 JVM 事件、方法调用、内存分配等详细信息、支持动态启停记录
- 事件驱动:捕获超过 200 种不同类型的事件(JDK 11+)
- 集成分析:与 Java Mission Control (JMC) 工具深度集成
Java飞行记录器(Java Flight Recorder,JFR)是JVM内置的低开销性能分析和故障排查工具,用于记录Java应用程序运行时的详细数据,类似飞机的“黑匣子”。它通过事件机制采集JVM和应用程序的运行时信息,包括CPU、内存、线程、垃圾回收(GC)、锁竞争等数据,帮助开发者定位性能瓶颈和异常问题。
📌 适用场景:性能调优、内存泄漏排查、高 CPU 使用率分析等
1.2. JFR 的发展历史
1.2.1. 关键里程碑
- JRockit Flight Recorder:JFR 最初是由 BEA Systems 开发的 JRockit JVM的一部分,当时被称为 JRockit Flight Recorder。
- Oracle 收购 Sun Microsystems:随着 Oracle 收购了 Sun Microsystems(Java的原始开发者)以及 BEA Systems,JFR 被集成到了 HotSpot JVM 中,并从 JDK 7u40 和 JDK 8u40开始被包含进去。此时,JFR 还是一个商业特性,需要许可证才能在生产环境中使用。
- JDK 11:JFR 2.0版本发布,提供了更丰富的功能集。JFR 成为了 OpenJDK 的一部分,无需额外安装。作为一个开源项目,不再需要商业许可证即可使用。
- JDK 14:引入了 JFR Event Streaming,允许实时处理 JFR 事件。
- JDK 17:稳定支持虚拟线程事件,并增强云原生环境兼容性。
1.2.2. Java Flight Recorder (JFR) 版本变化
| JDK版本 | 发布日期 | 主要变化与新特性 |
|---|---|---|
| JDK 7u40 | 2013年9月 | - JFR首次在Oracle JDK中作为商业特性引入 - 提供基本的事件记录功能,如GC、线程等 - JCMD控制 |
| JDK 8u40 | 2015年3月 | - 增加了更多的内置事件类型 - 改善了性能开销,减少了对应用程序的影响 -JMX动态控制 |
| JDK 9 | 2017年9月 | - 开始支持自定义事件 - 引入了更丰富的API用于编程控制JFR会话 |
| JDK 11 | 2018年9月 | - JFR成为OpenJDK的一部分(JEP 328) - JFR 2.0 版本、完全开源,社区可以贡献代码 - 支持JIT编译器事件,记录编译器活动和性能数据 - 对容器环境的支持,更好地适应Docker等容器化部署 - 改进了数据格式和压缩算法,提高了存储效率 |
| JDK 13 | 2019年9月 | - 引入了jdk.jfr.consumer模块,允许程序化地读取和分析JFR文件- 增强了事件过滤和配置选项 |
| JDK 14 | 2020年3月 | - 添加了对虚拟线程的支持(实验性) - 改进了事件元数据的可读性和灵活性 |
| JDK 15 | 2020年9月 | - 引入了新的事件类别,如jdk.VirtualThread*- 改进了JFR与容器环境的兼容性 |
| JDK 16 | 2021年3月 | - 支持动态调整采样率 - 增强了对云原生环境的支持 |
| JDK 17 | 2021年9月 | - 稳定版支持虚拟线程事件 - 改进了与Kubernetes等平台的集成 - 增强了安全性,包括对敏感数据的保护 |
| JDK 18 | 2022年3月 | - 引入了对GraalVM Native Image的支持 - 改进了内存管理和垃圾回收事件的详细程度 |
| JDK 19 | 2022年9月 | - 增强了对多租户环境的支持 - 改进了事件的时间戳精度 |
| JDK 20 | 2023年3月 | - 引入了新的事件类型,如jdk.CodeCacheFlush- 改进了对异步事件的支持 |
| JDK 21 | 2023年9月 | - 进一步增强了对虚拟线程的支持 - 改进了与Spring Boot等框架的集成 |
二、启用 JFR
2.1. 通过命令行参数启动
# JDK 8 需要添加以下参数,解锁商业功能
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder ...# JDK 11+ 开源版本直接启用
java -XX:StartFlightRecording:delay=5s,duration=60s,name=MyRecording,filename=recording.jfr ...
常用选项:
filename=recording.jfr:指定输出文件名duration=60s:设置录制时长delay=10s:延迟启动时间settings=profile:使用预定义配置文件(如profile,default)name=MyRecording:为录制会话命名
2.2. 运行时触发,使用jcmd工具
jcmd <PID> JFR.start duration=60s filename=recording.jfr
jcmd <PID> JFR.dump filename=partial.jfr
jcmd <PID> JFR.stop
2.3. 通过JMC(JDK Mission Control)启动
操作步骤:
- 打开JMC工具。
- 连接到正在运行的JVM实例。
- 在左侧导航栏选择“Flight Recorder”。
- 配置录制设置(如持续时间、事件类型等)。
- 点击“Start Recording”。
2.4 通过Spring Boot Actuator集成启动
2.4.1. 添加依赖
在pom.xml中添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId>
</dependency>
2.4.2. 使用HTTP接口启动
curl -X POST http://localhost:8080/actuator/jfr/start
curl -X POST http://localhost:8080/actuator/jfr/dump?filename=myapp_recording.jfr
curl -X POST http://localhost:8080/actuator/jfr/stop
三、JFR 事件
在 JFR中,一切皆为 Event!JFR 事件是 JFR 捕获和记录的最小数据单元,每个事件都代表了在特定时间点上系统或应用某个方面的信息。每条事件记录包含了多个数据字段,如时间戳、事件持续时间、以及其他与业务或系统状态相关的元数据。大部分的 Event,都有 Event 是在哪个线程发生的,Event 发生的时候这个线程的调用栈,Event 的持续时间。这就非常有用了,利用这些信息,我们可以回溯 Event 发生当时的情况。
3.1. 按来源分类
| 类别 | 说明 | 示例事件 |
|---|---|---|
| JVM 事件 | JVM 内部操作产生的事件 | jdk.GarbageCollection, jdk.JITCompilation |
| JDK 库事件 | JDK 类库(如 I/O、网络、集合)触发的事件 | jdk.FileRead, jdk.SocketWrite |
| OS 事件 | 操作系统级别的资源监控数据 | jdk.CPULoad, jdk.PhysicalMemory |
| 自定义事件 | 开发者定义的应用层事件 | com.example.OrderProcessEvent |
3.2. 按触发方式分类
- 阈值触发事件:当指标超过预设阈值时记录(如
jdk.CPULoad) - 周期采样事件:按固定时间间隔采集(如
jdk.ThreadAllocationStatistics) - 即时触发事件:特定操作发生时立即记录(如
jdk.ExceptionThrown)
3.3、关键内置事件
3.3.1. 垃圾回收相关
| 事件名称 | 作用 |
|---|---|
jdk.GarbageCollection | 记录 GC 暂停时间和原因(Young GC/Full GC) |
jdk.OldObjectSample | 跟踪可能引发内存泄漏的旧对象(需启用 -XX:StartFlightRecording=old-object-queue-size=256) |
3.3.2. 线程与锁
| 事件名称 | 作用 |
|---|---|
jdk.ThreadSleep | 记录线程睡眠时间 |
jdk.JavaMonitorWait | 监控 synchronized 锁等待时间 |
jdk.ThreadPark | 跟踪 LockSupport.park() 调用(如 AQS 锁) |
3.3.3. 异常与错误
| 事件名称 | 作用 |
|---|---|
jdk.ExceptionThrown | 记录所有异常抛出事件(包括堆栈跟踪) |
jdk.ErrorThrown | 记录严重错误事件(如 OutOfMemoryError) |
3.3.4. I/O 与网络
| 事件名称 | 作用 |
|---|---|
jdk.FileRead | 跟踪文件读取操作(包含路径和耗时) |
jdk.SocketRead | 记录 Socket 读取数据量及延迟 |
3.3.5. JIT 与类加载
| 事件名称 | 作用 |
|---|---|
jdk.JITCompilation | 记录方法编译耗时和优化级别 |
jdk.ClassLoad | 跟踪类加载过程及耗时 |
3.4. 多线程低开销设计与异步存储原理
3.4.1. 事件产生与多线程协作
- 多线程事件触发:
JFR 事件由业务线程在执行过程中主动生成(如方法调用、异常抛出、锁竞争等),每个线程独立维护线程本地缓冲区(Thread Local Buffer),直接以二进制格式缓存事件流。 - 线程隔离与无锁设计:
各线程仅操作自身缓冲区,避免全局锁竞争,确保事件记录低延迟(通常低于微秒级)。
3.4.2. 分级缓冲存储流程
-
线程本地缓冲区(Thread Local Buffer)
- 默认容量约 34KB,采用循环队列结构存储二进制事件数据。
- 缓冲区满时触发异步刷写(非阻塞),将数据批量推送至全局缓冲区。
-
全局缓冲区(Global Buffer)与持久化
- 全局缓冲区整合多线程事件流,由独立的
jfr守护线程负责管理。 - 后台线程将全局缓冲区的数据异步写入磁盘(生成
.jfr文件),完全分离业务线程与I/O操作,避免阻塞主逻辑。
- 全局缓冲区整合多线程事件流,由独立的
3.4.3. 高效性核心设计
- 二进制直接存储:
事件以二进制格式在内存中流转,跳过多余的序列化/反序列化步骤,减少 CPU 开销。 - 异步分层处理:
业务线程仅负责生成事件,缓冲区刷写与持久化由独立线程完成,通过批量合并降低 I/O 频率。 - 动态采样与可控开销:
JFR 支持按需配置采样率(如-XX:FlightRecorderOptions=stackdepth=128),通过 JVM 内部 Hook 实现非侵入式监控,无需代码插桩。
3.4.4. 自定义事件对业务的影响
- 轻量级托管机制:
开发者通过继承jdk.jfr.Event定义的事件,由 JFR 框架统一管理。调用commit()方法时,事件仅写入线程本地缓冲区,不占用业务线程额外时间。 - 背压(Backpressure)保护:
若事件产生速率超过持久化能力(如高频自定义事件),JFR 会触发背压机制,选择性丢弃低优先级事件或限制事件生成,防止资源耗尽。 - 可控的性能损耗:
合理使用自定义事件(如避免每秒超 10 万次高频提交),对业务延迟的影响通常可控制在 1%~2% 以内,极端场景需结合采样策略优化。
四、自定义事件开发
4.1. 自定义事件开发价值
通过自定义JFR事件,开发者可以:
- 业务指标可视化:记录订单创建、支付处理等关键业务指标
- 精准性能分析:追踪特定方法执行耗时、资源消耗
- 上下文关联:将JVM事件与业务逻辑关联分析
- 生产环境诊断:低开销实时监控生产系统
4.2. 自定义事件开发四部曲
4.2.1. 定义事件类
@Name("com.example.OrderCreated")
@Label("Order Created Event")
@Category("Business")
@Description("Records order creation information")
public class OrderCreatedEvent extends Event {@Label("Order ID")public String orderId;@Label("Total Amount")@Amount(Currency.CNY)public double amount;@Label("User Type")public UserType userType;@Label("Creation Duration")@Timespan(Timespan.MILLISECONDS)public long duration;
}
注解说明:
@Name: 定义事件的全局唯一标识符,推荐使用反向域名命名法(类似Java包名),避免与JVM内置事件冲突。@Label: 事件名称,在JMC等可视化工具中作为显示名称。@Category: JMC中的分类显示,在JMC左侧导航树状呈现。@Description: 提供事件的详细文档说明吗,在JMC中通过"Show Description"查看。
4.2.2. 触发事件记录
public class OrderService {public void createOrder(OrderRequest request) {OrderCreatedEvent event = new OrderCreatedEvent();if (event.isEnabled()) {long start = System.nanoTime();// 业务逻辑执行...event.orderId = generatedId;event.amount = calculateAmount();event.userType = getCurrentUserType();event.duration = (System.nanoTime() - start) / 1_000_000;event.commit();}}
}
4.2.2. 事件注册与启用
@Registered(true)
public class OrderCreatedEvent extends Event {//...
}
动态启用配置:
jcmd <PID> JFR.configure threshold=10ms stacktrace=true path-to-gc-roots=true
4.2.4. 事件数据分析
使用JMC分析:
public static void analyzeJfr(File recordingFile) throws IOException {try (RecordingStream rs = new RecordingStream(recordingFile)) {rs.onEvent("com.example.OrderCreated", event -> {System.out.printf("订单%s 金额%.2f 耗时%dms%n",event.getString("orderId"),event.getDouble("amount"),event.getLong("duration"));});rs.start();}
}
五、高级技巧
5.1 异步事件处理
@Async
public class AsyncPaymentEvent extends Event {//...
}
5.2 阈值控制
@Threshold("20 ms")
public class SlowMethodEvent extends Event {//...
}
5.3 自定义转换器
public class UserTypeConverter extends Converter<UserType> {public String toString(UserType type) {return type.name().toLowerCase();}
}public class OrderCreatedEvent extends Event {@Converter(UserTypeConverter.class)public UserType userType;
}
六、总结
通过自定义JFR事件,开发者可以获得:
- 生产环境细粒度监控能力
- 业务与JVM事件的关联分析
- 传统日志无法实现的性能洞察
建议结合JMC可视化工具和jfr命令行工具,构建完整的性能监控体系。下一篇来具体介绍使用JMC进行JFR性能分析指南。
最佳实践:从关键业务路径开始逐步增加事件埋点,通过持续的性能分析迭代优化事件配置。
相关文章:
JVM生产环境问题定位与解决实战(三):揭秘Java飞行记录器(JFR)的强大功能
提到飞行记录器,或许你的脑海中并未立刻浮现出清晰的画面,但一说起“黑匣子”,想必大多数人都能恍然大悟,知晓其重要性及用途。在航空领域,黑匣子作为不可或缺的设备,默默记录着飞行过程中的每一项关键数据…...
爬虫框架与库
爬虫框架与库是用于网络数据抓取的核心工具,帮助开发者高效地从网页中提取结构化数据。 Requests:用于发送HTTP请求。 BeautifulSoup:用于解析HTML和XML。 Scrapy:强大的爬虫框架,适合大规模爬取。 Selenium&#…...
PyTorch常用函数总结(持续更新)
本文主要记录自己在用 PyTorch复现经典模型 过程中遇到的一些函数及用法,以期对 常见PyTorch函数 更加熟练~ 官方Docs:PyTorch documentation — PyTorch 2.6 documentation 目录 数据层面 torch.sign(tensor) torch.tensor(np.eye(3)[y]) torch.on…...
代码异常(js中push)NO.4
1. 环境 Vue3,Element Plsu 2. 示例代码 const { updateBy, updateTime, ...curObj } form.valuecurObj.id props.tableData.length 1var newTableData props.tableData.push(curObj)updateTableData(newTableData)3. 情景描述 newTableData变成了整数&#…...
Anaconda 2025 最新版安装与Python环境配置指南(附官方下载链接)
一、软件定位与核心功能 Anaconda 2025 是Python/R数据科学集成开发平台,预装1500科学计算库,新增AI模型可视化调试、多环境GPU加速等特性。相较于传统Python安装,其优势包括: 环境隔离:通过conda工具实现多版本Pyth…...
Vue 中动态实现进度条
在 Vue 中动态实现进度条,基本上有两种常见的方法:直接通过 Vue 数据绑定控制样式,或者利用外部库来实现更复杂的功能。我们会深入探讨这两种方式,并且详细说明每种方法的实现步骤、优缺点以及使用场景。 1. 使用 Vue 数据绑定来…...
CSS滚动条原理与自定义样式指南,CSS滚动条样式失效,滚动条样式无效,-webkit-scrollbar无效,overflow不显示滚动条
滚动内容形成的必要条件 CSS Overflow属性解析 MDN官方文档-Overflow属性 菜鸟教程-Overflow属性 overflow 属性控制内容溢出元素框时在对应的元素区间内是否添加滚动条。 值描述visible默认值。内容不会被修剪,会呈现在元素框之外。hidden内容会被修剪…...
Three.js 入门(辅助、位移、父子关系、缩放旋转、响应式布局)
本篇主要学习内容 : 三维坐标系与辅助坐标系物体位移与父子元素物体的缩放与物体的旋转设置响应式画布与全屏控制 点赞 关注 收藏 学会了 本文使用 Three.js 的版本:171 基于 Vue3vite开发调试 1.三维坐标系与辅助坐标系 1.1) 导入three和轨道控制器 // 导入…...
python算法-用递归打印数字3的幂--Day017
文章目录 前言采用创新方式,精选趣味、实用性强的例子,从不同难度、不同算法、不同类型和不同数据结构进行总结,全面提升算法能力。例1.用递归打印数字例2.相对排名 总结 前言 采用创新方式,精选趣味、实用性强的例子,…...
Selenium 与 Coze 集成
涵盖两者的基本概念、集成步骤、代码示例以及相关注意事项。 基本概念 Selenium:是一个用于自动化浏览器操作的工具集,支持多种浏览器(如 Chrome、Firefox 等),能够模拟用户在浏览器中的各种操作,如点击、输入文本、选择下拉框等,常用于 Web 应用的自动化测试。Coze:它…...
AWS CLI将读取器实例添加到Amazon Aurora集群
Amazon Aurora是AWS提供的一种兼容MySQL和PostgreSQL的关系数据库服务。Aurora集群由一个写入器实例和多个读取器实例组成,可以提供高可用性、高性能和可扩展性。在本文中,我们将介绍如何使用AWS命令行界面(CLI)将读取器实例添加到现有的Aurora集群中。 © ivwdcwso (ID: u…...
NTS库学习,找bug中......
基础知识 Coordinate: 表示一个二维坐标点,包括 X 和 Y 坐标值。 CoordinateSequence: 由一系列 Coordinate 对象组成的序列,可以表示线、多边形等几何对象的顶点。 CoordinateFilter: 用于对几何对象的坐标进行过滤或修改的接口。 Geometry: 表示一个几…...
五十天精通硬件设计第40天-硬件测试流程
目录 一、硬件测试流程概述 二、详细测试流程 1. 需求分析与测试计划 2. 测试环境搭建 3. 测试执行 3.1 基本功能测试 3.2 性能测试 3.3 环境与可靠性测试 3.4 安全与合规性测试 4. 问题分析与调试 5. 回归测试与报告输出 三、关键注意事项 四、常见问题与解决 五…...
R语言安装教程(附安装包)R语言4.3.2版本安装教程
文章目录 前言一、安装包下载二、R-4.3.2安装步骤三、rtools43安装步骤四、RStudio安装步骤 前言 本教程将详细、全面地为你介绍在 Windows 系统下安装 R 语言 4.3.2 的具体步骤。无论你是初涉数据领域的新手,还是希望更新知识体系的专业人士,只要按照本…...
数据库 安装initializing database不通过
出现一下情况时: 处理方法: 将自己的电脑名称 中文改成英文 即可通过...
自动驾驶两个传感器之间的坐标系转换
有两种方式可以实现两个坐标系的转换。 车身坐标系下一个点p_car,需要转换到相机坐标系下,旋转矩阵R_car2Cam,平移矩阵T_car2Cam。点p_car在相机坐标系下记p_cam. 方法1:先旋转再平移 p_cam T_car2Cam * p_car T_car2Cam 需要注…...
信号——进程间通信(20250225)
1. 信号 管道:进程间数据通信(同步通信) 信号:进程间通信,用来发送通知(异步通信,中断) 1)同步通信:发送端和接收端,使用同一时钟通信 异步通信:发送端和接收端使用不同时钟通信 …...
transformer架构嵌入层位置编码之动态NTK-aware位置编码
前文,我们已经构建了一个小型的字符级语言模型,是在transformer架构基础上实现的最基本的模型,我们肯定是希望对该模型进行改进和完善的。所以我们的另外一篇文章也从数据预处理、模型架构、训练策略、评估方法、代码结构、错误处理、性能优化等多个方面提出具体的改进点,但…...
东信营销科技巨额补贴仍由盈转亏:毛利率大幅下滑,现金流告急
《港湾商业观察》施子夫 近期,东信营销科技有限公司(以下简称,东信营销科技)递表港交所,联席保荐机构为海通国际和中银国际。 东信营销科技的国内运营主体为深圳市东信时代信息技术有限公司。尽管期内收入规模有所提…...
[电感、磁珠、0欧姆电阻]的区别与应用特性
1. 电感(Inductor) 基础特性: 储能元件:通过磁场存储能量,阻碍电流突变()。 核心参数:电感值(L)、额定电流、直流电阻(DCR)、自谐振频率(SRF)。 频率特性:感抗 ,(通直流、阻交流),低频时阻抗低,高频时阻抗高(但受SRF限制)。 电路符号及实物:多为绕线结…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
背包问题双雄:01 背包与完全背包详解(Java 实现)
一、背包问题概述 背包问题是动态规划领域的经典问题,其核心在于如何在有限容量的背包中选择物品,使得总价值最大化。根据物品选择规则的不同,主要分为两类: 01 背包:每件物品最多选 1 次(选或不选&#…...
