Spring Boot 线程池自定义拒绝策略:解决任务堆积与丢失问题
如何通过自定义线程池提升系统稳定性
背景
在高并发系统中,线程池管理至关重要。默认线程池可能导致:
- 资源浪费(创建过多线程导致 OOM)
- 任务堆积(队列满后任务被拒绝)
- 任务丢失(默认拒绝策略丢弃任务
为了防止这些问题,我们使用 Spring Boot 自定义线程池,并优化 异常处理 和 拒绝策略。
线程池方案设计
在 ExecutorConfig 类中,我们定义了两个线程池:
- myExecutor:用于普通任务,采用CallerRunsPolicy 避免任务丢失。
- oneExecutor:用于信号计算任务(单线程模式),具有 自定义异常处理 和 阻塞式拒绝策略。
代码解析
线程池 myExecutor(通用任务池)
@Bean(name = "myExecutor")
public Executor myExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(threadProperties.getCorePoolSize());executor.setMaxPoolSize(threadProperties.getMaxPoolSize());executor.setQueueCapacity(threadProperties.getQueueCapacity());executor.setThreadNamePrefix("signal-executor-");executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;
}
设计要点:
CallerRunsPolicy:线程池满了,主线程执行任务,防止丢失但可能影响性能。
线程池 oneExecutor(单线程计算池)
@Bean(name = "oneExecutor")
public Executor oneExecutor() {ThreadFactory threadFactory = new BasicThreadFactory.Builder().uncaughtExceptionHandler(new MyThreadException()).namingPattern("one-thread-%s").build();ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(1);executor.setMaxPoolSize(1);executor.setQueueCapacity(1);executor.setThreadFactory(threadFactory);executor.setThreadGroup(new ThreadGroup("1"));executor.setRejectedExecutionHandler(new CustomRejectedExecutionHandler());executor.initialize();return executor;
}
设计要点:
单线程池(保证任务顺序执行),如果无须,那就按照当前的服务节点配置来设置参数
自定义异常处理(防止线程因异常崩溃)
自定义拒绝策略(任务队列满时阻塞等待)
自定义异常处理
class MyThreadException implements Thread.UncaughtExceptionHandler {@Overridepublic void uncaughtException(Thread t, Throwable e) {log.error("异常: {},线程: {}", ExceptionUtils.getStackTrace(e), t.getName());}
}
作用:防止线程因未捕获异常直接终止,提升系统稳定性。当然这个是处理线程池中子任务处理业务逻辑的时候发生业务异常的处理方式,除此之外还有其他的解决方案
异常处理
- afterExecute() 处理异常(可扩展) :用于处理执行过程中抛出的异常
- uncaughtExceptionHandler 处理未捕获异常(默认 JVM 打印堆栈): 用于处理线程未捕获的异常;
- RejectedExecutionHandler 处理任务拒绝:处理任务被拒绝的情况。
处理顺序:
- 当任务执行时,如果任务抛出异常,它会首先被 afterExecute() 捕获,并且你可以在这里进行进一步的处理。
- 如果任务中的异常没有被 afterExecute() 捕获或处理,且是未捕获异常,它会交由 uncaughtExceptionHandler 进行处理。
- RejectedExecutionHandler 是处理线程池拒绝接受新任务的情况,这通常和任务执行过程中的异常无关,主要处理线程池饱和时的情况。
注意:beforeExecute() 在任务开始执行前调用,通常用于准备工作;
异常处理上,beforeExecute() 不会直接处理任务执行过程中的异常,但可以捕获并处理自己内部的异常;
相关源码分析:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 1️⃣ 线程池当前线程数 < corePoolSize,则尝试新增核心线程执行任务
if (workerCountOf© < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 2️⃣ 线程池已满,尝试加入工作队列
if (isRunning© && workQueue.offer(command)) {
int recheck = ctl.get();
if (!isRunning(recheck) && remove(command))
reject(command); // 任务队列中的任务被拒绝
else if (workerCountOf(recheck) == 0)
addWorker(null, false); // 防止线程池为空,确保有线程执行任务
}
// 3️⃣ 线程池满且队列满,尝试新增非核心线程
else if (!addWorker(command, false))
reject(command); // 线程池已满,拒绝任务
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 允许中断
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// 1️⃣ 执行任务
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run(); // ⚠ 任务执行点
} catch (RuntimeException x) {
thrown = x;
throw x;
} catch (Error x) {
thrown = x;
throw x;
} catch (Throwable x) {
thrown = x;
throw new Error(x);
} finally {
afterExecute(task, thrown); // 2️⃣ 任务执行后的扩展方法
}
task = null;
w.completedTasks++;
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly); // 3️⃣ 任务异常退出,删除该线程
}
}
自定义拒绝策略-重新放回队列中
public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {try {if (!executor.isShutdown()) {log.info("队列已满,阻塞等待...");executor.getQueue().put(r);log.info("任务已加入队列");}} catch (Exception e) {log.error("拒绝策略异常", e);}}
}
作用:
默认拒绝策略丢弃任务,而此策略会阻塞等待,确保任务不丢失。
适用于任务量较大,但不能丢失任务的场景(如消息队列处理)
自定义拒绝策略-主线程执行
/*** 自定义线程池,防止使用默认线程池导致内存溢出** @param* @return* @author bu.junjie* @date 2021/11/10 10:00*/@Bean(name = "myExecutor")public Executor myExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(threadProperties.getCorePoolSize());executor.setMaxPoolSize(threadProperties.getMaxPoolSize());executor.setQueueCapacity(threadProperties.getQueueCapacity());executor.setThreadNamePrefix("signal-executor-");// 使用此策略,如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行,阻塞主线程executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}
适用场景
✅ 高并发请求(如 HTTP 任务)
✅ 后台数据处理(如日志分析、批量计算)
✅ 长时间任务(如大文件处理、消息队列消费)
总结
- 自定义线程池 防止资源浪费,提升吞吐量。
- 异常处理 避免线程因未捕获异常而终止。
- 优化拒绝策略 防止任务丢失,提高系统可靠性。
线程池优化是高并发系统的关键,希望本篇博客能帮助你更好地理解和应用线程池! 🚀🚀🚀
完整代码示例
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import javax.annotation.Resource;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;/*** 线程池配置参数** @version 1.0.0* @createTime 2025-11-09 14:01*/
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {@Resourceprivate ThreadProperties threadProperties;/*** 自定义线程池,防止使用默认线程池导致内存溢出** @param* @return* @author bu.junjie* @date 2021/11/10 10:00*/@Bean(name = "myExecutor")public Executor myExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(threadProperties.getCorePoolSize());executor.setMaxPoolSize(threadProperties.getMaxPoolSize());executor.setQueueCapacity(threadProperties.getQueueCapacity());executor.setThreadNamePrefix("signal-executor-");// 使用此策略,如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行,阻塞主线程executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}/*** 信号计算时的线程池(1号线程池)** @param* @return* @author bu.junjie* @date 2022/1/5 13:01*/@Bean(name = "oneExecutor")public Executor oneExecutor() {ThreadFactory threadFactory = new BasicThreadFactory.Builder().uncaughtExceptionHandler(new MyThreadException()).namingPattern("one-thread-%s").build();ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(1);executor.setMaxPoolSize(1);executor.setThreadFactory(threadFactory);executor.setQueueCapacity(1);executor.setThreadGroup(new ThreadGroup("1"));executor.setRejectedExecutionHandler(new CustomRejectedExecutionHandler());executor.initialize();return executor;}class MyThreadException implements Thread.UncaughtExceptionHandler {/*** Method invoked when the given thread terminates due to the* given uncaught exception.* <p>Any exception thrown by this method will be ignored by the* Java Virtual Machine.** @param t the thread* @param e the exception*/@Overridepublic void uncaughtException(Thread t, Throwable e) {log.error("MyThreadException is exception=【{}】,Thread = 【{}】", ExceptionUtils.getStackTrace(e), t.getName());}}/*** 拒绝策略优化** @param* @author bu.junjie* @date 2022/1/8 14:06* @return*/public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {try {// 核心改造点,由blockingqueue的offer改成put阻塞方法if (!executor.isShutdown()) {long start = System.currentTimeMillis();log.info("当前阻塞队列已满开始请求存放队列束!!!");executor.getQueue().put(r);log.info("存放阻塞队列成功,阻塞时间time = 【{}】", System.currentTimeMillis() - start);}} catch (Exception e) {e.printStackTrace();}}}}
思考
为什么拒绝策略要重新抛出异常?
我们会发现默认的四种拒绝策略在处理完业务逻辑之后还会重新抛出异常,就算你是自定义的拒绝策略也需要重新抛出异常,为什么呢?不抛出会怎么样?
如果不抛出异常,调用方(业务代码)无法感知任务被拒绝,可能导致任务丢失或业务逻辑异常。
场景分析
当线程池队列满了时,会触发 rejectedExecution 方法。如果我们只是记录日志,而不抛出异常:
- 主线程会继续执行,但任务并未真正执行,业务方无法感知到这个问题。
- 可能导致数据丢失,尤其是在关键业务(如支付、订单、消息处理)场景中。
重新抛出异常的好处
✅ 保证调用方可以感知任务拒绝,决定是否降级处理、重试或报警。
✅ 防止静默丢失任务,保证业务的可靠性。
✅ 与 Spring 线程池默认行为保持一致,防止意外吞掉异常。
代码示例
❌ 错误示例(未抛出异常,可能导致任务丢失)
public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {try {if (!executor.isShutdown()) {log.warn("队列已满,任务阻塞等待...");executor.getQueue().put(r); // 可能抛出异常log.info("任务已放入队列");}} catch (InterruptedException e) {Thread.currentThread().interrupt(); // 仅恢复中断状态,但未通知调用方}}
}
问题:
调用方不会收到异常,以为任务已经成功执行,但其实可能丢失了。
例如,在支付系统中,如果订单更新任务丢失,可能导致订单状态未更新。
✅ 正确示例(重新抛出异常,保证调用方可感知)
public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {try {if (!executor.isShutdown()) {log.warn("队列已满,阻塞等待...");executor.getQueue().put(r);log.info("任务成功进入队列");return; // 任务成功加入队列后不需要抛异常}} catch (InterruptedException e) {Thread.currentThread().interrupt(); // 恢复线程中断状态throw new RejectedExecutionException("任务提交被中断", e);} catch (Exception e) {log.error("任务拒绝策略发生异常", e);throw new RejectedExecutionException("自定义拒绝策略异常", e);}}
}
改进点:
任务成功放入队列时不会抛异常,避免不必要的错误。
如果 put() 失败,抛出 RejectedExecutionException,让业务方感知。
捕获 InterruptedException 并恢复中断状态,避免影响后续任务。
其实这个原因和为什么需要恢复线程中断一样的逻辑,也是为了让调用方感知到
业务方如何处理异常?
如果 rejectedExecution 抛出 RejectedExecutionException,业务代码可以捕获异常并进行降级,例如:
try {executor.execute(task);
} catch (RejectedExecutionException e) {log.error("线程池已满,任务执行失败,进行降级处理", e);// 业务降级策略,例如:saveToDatabaseForLaterProcessing(task);
}
降级方案:如果线程池拒绝任务,可以存入 数据库、MQ 或 重试队列,避免任务丢失。
结论
🚀 必须重新抛出异常,否则:
- 任务可能悄悄丢失,业务方无法感知。
- 可能影响数据一致性(如支付、订单、日志处理)。
- 业务代码无法主动补救(重试、降级等)。
最佳实践:
- 成功放入队列 → 不抛异常
- 任务无法处理 → 抛出 RejectedExecutionException,让调用方感知
这样可以既保证任务不丢失,又确保调用方有能力处理拒绝任务!🔥
自定义拒绝策略put()方法?
其实默认拒绝策略是offer()方法是非阻塞的,也就是只要队列中的任务只要有,那就去创建子线程,直至触发拒绝策略
✅ 正确示例
public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {try {System.out.println("队列已满,阻塞等待...");executor.getQueue().put(r); // 阻塞等待队列有空位System.out.println("任务重新加入队列:" + r.toString());} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RejectedExecutionException("任务提交失败,线程被中断", e);}}
}
相关文章:

Spring Boot 线程池自定义拒绝策略:解决任务堆积与丢失问题
如何通过自定义线程池提升系统稳定性 背景 在高并发系统中,线程池管理至关重要。默认线程池可能导致: 资源浪费(创建过多线程导致 OOM)任务堆积(队列满后任务被拒绝)任务丢失(默认拒绝策略丢…...

解锁摄影潜能:全面解析相机镜头的选择与使用逻辑
目录 一、镜头分类:从焦距到用途的底层逻辑 (一)按焦距和视角分类(一级分类) (二)按特殊用途分类(一级分类) 二、参数解码:超越 “光圈越大越好” 的思维定…...

【Unity】从父对象中获取子对象组件的方式
1.GetComponentInChildren 用于获取对与指定组件或游戏对象的任何子级相同的游戏对象上的组件类型的引用。 该方法在Unity脚本API的声明格式为: public T GetComponentInChildren(bool includeInactive false) includeInactive参数(可选)…...

第六届MathorCup高校数学建模挑战赛-A题:淡水养殖池塘水华发生及池水自净化研究
目录 摘要 1 问题的重述 2 问题的分析 2.1 问题一的分析 2.2 问题二的分析 2.3 问题三的分析 2.4 问题四的分析 2.5 问题五的分析 3. 问题的假设 4. 符号说明 5. 模型的建立与求解 5.1 问题一的建模与求解 5.1.1 分析对象与指标的选取 5.1.2 折线图分析 5.1.3 相关性分析 5.1.4…...

webpack【初体验】使用 webpack 打包一个程序
打包前 共 3 个文件 dist\index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Webpack 示例&…...

<论文>DeepSeek-R1:通过强化学习激励大语言模型的推理能力(深度思考)
一、摘要 本文跟大家来一起阅读DeepSeek团队发表于2025年1月的一篇论文《DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning | Papers With Code》,新鲜的DeepSeek-R1推理模型,作者规模属实庞大。如果你正在使用Deep…...

公司配置内网穿透方法笔记
一、目的 公司内部有局域网,局域网上有ftp服务器,有windows桌面服务器; 在内网环境下,是可以访问ftp服务器以及用远程桌面登录windows桌面服务器的; 现在想居家办公时,也能访问到公司内网的ftp服务器和win…...

python爬虫--简单登录
1,使用flask框架搭建一个简易网站 后端代码app.py from flask import Flask, render_template, request, redirect, url_for, sessionapp Flask(__name__) app.secret_key 123456789 # 用于加密会话数据# 模拟用户数据库 users {user1: {password: password1}…...

人工智能浪潮下脑力劳动的变革与重塑:挑战、机遇与应对策略
一、引言 1.1 研究背景与意义 近年来,人工智能技术发展迅猛,已成为全球科技领域的焦点。从图像识别、语音识别到自然语言处理,从智能家居、智能交通到智能医疗,人工智能技术的应用几乎涵盖了我们生活的方方面面,给人…...

ESP32-S3驱动步进电机以及梯形加减速库调用
一、硬件连接说明 电机与驱动器连接: 42BYGH39-401A步进电机有4根引线,分别连接到驱动器(如TB6600)的电机接口上。 电机引脚A、A-、B、B-分别连接到驱动器对应的电机接口。 驱动器与ESP32-S3连接: ESP32-S3的GPIO引脚…...

【CubeMX+STM32】SD卡 文件系统读写 FatFs+SDIO+DMA
本篇,将使用CubeMXKeil,创建一个SD卡的 FatFSSDIODMA 文件系统读写工程。 目录 一、简述 二、CubeMX 配置 FatFSSDIO DMA 三、Keil 编辑代码 四、实验效果 实现效果,如下图: 一、简述 上两篇,已循序渐进讲解了SD、…...

Kotlin 2.1.0 入门教程(十)if、when
if 表达式 if 是一个表达式,它会返回一个值。 不存在三元运算符(condition ? then : else),因为 if 在这种场景下完全可以胜任。 var max aif (a < b) max bif (a > b) {max a } else {max b }max if (a > b) a…...

AJAX项目——数据管理平台
黑马程序员视频地址: 黑马程序员——数据管理平台 前言 功能: 1.登录和权限判断 2.查看文章内容列表(筛选,分页) 3.编辑文章(数据回显) 4.删除文章 5.发布文章(图片上传࿰…...

华为云搭建微信小程序商城后台
目录 安装宝塔界面 配置运行环境 1. 修改默认用户名密码 2. 修改默认端口号 3. 安装依赖软件 4. 安装商城 配置商城 1. 点击下一步进行商城环境检测 2. 将安装ShopXO成功后的弹窗信息填写到配置界面 3. 点击安装 发布小程序 源代码地址 1. 下载HBuilderX 2. 导入插…...

5、大模型的记忆与缓存
文章目录 本节内容介绍记忆Mem0使用 mem0 实现长期记忆 缓存LangChain 中的缓存语义缓存 本节内容介绍 本节主要介绍大模型的缓存思路,通过使用常见的缓存技术,降低大模型的回复速度,下面介绍的是使用redis和mem0,当然redis的语义…...

Windows下AMD显卡在本地运行大语言模型(deepseek-r1)
Windows下AMD显卡在本地运行大语言模型 本人电脑配置第一步先在官网确认自己的 AMD 显卡是否支持 ROCm下载Ollama安装程序模型下载位置更改下载 ROCmLibs先确认自己显卡的gfx型号下载解压 替换替换rocblas.dll替换library文件夹下的所有 重启Ollama下载模型运行效果 本人电脑配…...

代码随想录day09
151.反转字符串中的单词,需二刷 //先去除多余空格,再反转所有字符,再反转单词,即可反转字符串中的单词 void removeWhiteSpace(string& s){int slowIndex 0;for(int fastIndex 0; fastIndex < s.size(); fastIndex){if(…...

Racecar Gym 总结
1.Racecar Gym 简介 Racecar Gym 是一个基于 PyBullet 物理引擎 的自动驾驶仿真平台,提供 Gymnasium(OpenAI Gym) 接口,主要用于强化学习(Reinforcement Learning, RL)、多智能体竞速(Multi-Ag…...

【C++高并发服务器WebServer】-15:poll、epoll详解及实现
本文目录 一、poll二、epoll2.1 相对poll和select的优点2.2 epoll的api2.3 epoll的demo实现2.5 epoll的工作模式 一、poll poll是对select的一个改进,我们先来看看select的缺点。 我们来看看poll的实现。 struct pollfd {int fd; /* 委托内核检测的文件描述符 */s…...

Visual Studio 2022 中使用 Google Test
要在 Visual Studio 2022 中使用 Google Test (gtest),可以按照以下步骤进行: 安装 Google Test:确保你已经安装了 Google Test。如果没有安装,可以通过 Visual Studio Installer 安装。在安装程序中,找到并选择 Googl…...

Office/WPS接入DeepSeek等多个AI工具,开启办公新模式!
在现代职场中,Office办公套件已成为工作和学习的必备工具,其功能强大但复杂,熟练掌握需要系统的学习。为了简化操作,使每个人都能轻松使用各种功能,市场上涌现出各类办公插件。这些插件不仅提升了用户体验,…...

Meta AI 最近推出了一款全新的机器学习框架ParetoQ,专门用于大型语言模型的4-bit 以下量化
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

操作系统—进程与线程
补充知识 PSW程序状态字寄存器PC程序计数器:存放下一条指令的地址IR指令寄存器:存放当前正在执行的指令通用寄存器:存放其他一些必要信息 进程 进程:进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位…...

团队:前端开发工期参考 / 防止工期不足、过足、工期打架
一、前端开发工期参考 序号功能 / 模块 / 页面 / 描述pc端(数值为比例)小程序端(数值为比例)1简单页面 / 常规页面1:12复杂页面(功能复杂 / 逻辑复杂)1:1.5 / 1:2 / …...

APL语言的云计算
APL语言的云计算:一种灵活而高效的编程方式 引言 随着信息技术的迅猛发展,云计算已经成为现代计算的重要组成部分。云计算不仅带来了计算资源的高效利用,也引发了新一轮的技术革命。在这个背景下,APL(A Programming …...

idea启动报错# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffccf76e433
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc0x00007ffccf76e433, pid17288, tid6696 # # JRE version: (11.0.248) (build ) # Java VM: OpenJDK 64-Bit Server VM (11.0.248-LTS, mixed mode, sharing, tiered, compressed oops, g1 gc, windows-amd64) 不知道为什么…...

C++拷贝构造函数与运算符重载应该注意的一个问题?
看下面的例子: class TestClass { public:char* _pdata;size_t _nLength;public:TestClass(const TestClass& other) {_nLength other._nLength;_pdata new char[_nLength];memcpy((void*)_pdata,other._pdata, _nLength 1);}TestClass(const char* pstr) {…...

[7] 游戏机项目说明
[7] 游戏机项目说明 在这节课中,我们将学习如何基于FreeRTOS开发一个简单的游戏项目。我们会使用一个开源项目nwatch,它是一个基于STM32的开源手表,包含了三个游戏。我们的目标是将这个游戏移植到我们的开发板上,并逐步使用FreeR…...

“深入浅出”系列之C++:(20)C++17
C17的新拓展 并行算法: C17引入了并行STL算法,允许使用多个线程并行处理元素,提高了在多核系统上的性能。 示例代码:std::sort(std::execution::par, v.begin(), v.end()); 类模板参数推导(CTAD)&#…...

.net一些知识点5
1.dot Net带out的参数如何使用 string name;//假设这个参数带out TestMethod(1,out name);//一定要有out 方法体中,一定要有out参数的赋值,并且能输出 2.参数的传递方式有哪些 a.值传递 b.引用传递 ref c.输出传递 out 3.设计模式知道哪些 3.us…...