当前位置: 首页 > article >正文

Java 虚拟线程并发最佳实践:高并发编程新范式

Java 虚拟线程并发最佳实践高并发编程新范式今天我们来聊聊 Java 虚拟线程的并发最佳实践这是 Java 21 带来的革命性特性。一、虚拟线程概述虚拟线程Virtual Threads是 Java 21 引入的轻量级线程实现它彻底改变了 Java 的并发编程模型。与传统的操作系统线程平台线程相比虚拟线程具有以下特点极低的创建成本可以轻松创建数百万个虚拟线程自动管理由 JVM 自动调度无需手动管理线程池阻塞友好阻塞操作不会占用操作系统线程兼容性好与现有 Thread API 完全兼容二、虚拟线程 vs 平台线程1. 性能对比public class ThreadComparison { public static void main(String[] args) throws InterruptedException { // 测试平台线程 long startPlatform System.currentTimeMillis(); try (var executor Executors.newFixedThreadPool(1000)) { IntStream.range(0, 10_000).forEach(i - { executor.submit(() - { Thread.sleep(Duration.ofSeconds(1)); return i; }); }); } long platformTime System.currentTimeMillis() - startPlatform; System.out.println(Platform threads: platformTime ms); // 测试虚拟线程 long startVirtual System.currentTimeMillis(); try (var executor Executors.newVirtualThreadPerTaskExecutor()) { IntStream.range(0, 10_000).forEach(i - { executor.submit(() - { Thread.sleep(Duration.ofSeconds(1)); return i; }); }); } long virtualTime System.currentTimeMillis() - startVirtual; System.out.println(Virtual threads: virtualTime ms); } }2. 资源占用对比特性平台线程虚拟线程内存占用~1 MB~几百字节创建时间~毫秒级~微秒级最大数量~几千~数百万上下文切换内核态用户态三、虚拟线程的核心用法1. 创建虚拟线程public class VirtualThreadCreation { // 方式 1使用 Thread.ofVirtual() public void createVirtualThread1() { Thread virtualThread Thread.ofVirtual() .name(my-virtual-thread) .unstarted(() - { System.out.println(Running in virtual thread: Thread.currentThread()); }); virtualThread.start(); } // 方式 2使用 Thread.startVirtualThread() public void createVirtualThread2() { Thread virtualThread Thread.startVirtualThread(() - { System.out.println(Running in virtual thread: Thread.currentThread()); }); } // 方式 3使用 Executors.newVirtualThreadPerTaskExecutor() public void createVirtualThread3() { try (var executor Executors.newVirtualThreadPerTaskExecutor()) { executor.submit(() - { System.out.println(Running in virtual thread pool); }); } } }2. 虚拟线程与同步代码虚拟线程特别适合处理阻塞操作Service public class UserService { private final RestTemplate restTemplate; private final UserRepository userRepository; public UserService(RestTemplate restTemplate, UserRepository userRepository) { this.restTemplate restTemplate; this.userRepository userRepository; } // 虚拟线程下阻塞操作不会占用 OS 线程 public User fetchUserWithDetails(String userId) { // 数据库查询 - 阻塞操作 User user userRepository.findById(userId) .orElseThrow(() - new UserNotFoundException(userId)); // HTTP 调用 - 阻塞操作 UserProfile profile restTemplate.getForObject( https://api.example.com/users/{id}/profile, UserProfile.class, userId); user.setProfile(profile); return user; } }四、最佳实践1. 避免使用 synchronized 和 ReentrantLock虚拟线程在阻塞时会释放载体线程但使用synchronized或ReentrantLock时会钉住pin载体线程// 不推荐会钉住载体线程 public synchronized void synchronizedMethod() { // 长时间操作 } // 推荐使用 ReentrantLock 配合 try-lock private final ReentrantLock lock new ReentrantLock(); public void betterLocking() { lock.lock(); try { // 长时间操作 } finally { lock.unlock(); } } // 更好的选择使用 java.util.concurrent 中的并发集合 private final ConcurrentHashMapString, User userCache new ConcurrentHashMap(); public User getUser(String userId) { return userCache.computeIfAbsent(userId, this::fetchUserFromDatabase); }2. 合理使用线程局部变量public class ThreadLocalBestPractice { // 不推荐ThreadLocal 在虚拟线程下会有性能问题 private static final ThreadLocalSimpleDateFormat dateFormat ThreadLocal.withInitial(() - new SimpleDateFormat(yyyy-MM-dd)); // 推荐使用 DateTimeFormatter线程安全 private static final DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy-MM-dd); // 或者使用 ScopedValueJava 21 private static final ScopedValueString requestId ScopedValue.newInstance(); public void processRequest(String reqId) { ScopedValue.where(requestId, reqId).run(() - { // 在作用域内使用 requestId System.out.println(Processing request: requestId.get()); // 调用其他方法 processData(); }); } private void processData() { // 可以直接获取 requestId System.out.println(Request ID in sub-method: requestId.get()); } }3. 正确处理异常public class VirtualThreadExceptionHandling { public void handleExceptions() { try (var executor Executors.newVirtualThreadPerTaskExecutor()) { FutureString future executor.submit(() - { if (someCondition()) { throw new BusinessException(Something went wrong); } return Success; }); try { String result future.get(); System.out.println(Result: result); } catch (ExecutionException e) { // 处理业务异常 Throwable cause e.getCause(); if (cause instanceof BusinessException) { System.err.println(Business error: cause.getMessage()); } else { System.err.println(Unexpected error: cause.getMessage()); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println(Operation interrupted); } } } }4. 资源管理public class VirtualThreadResourceManagement { // 使用 try-with-resources 确保资源释放 public void processWithResources() { try (var executor Executors.newVirtualThreadPerTaskExecutor(); var connection dataSource.getConnection()) { ListFutureResult futures new ArrayList(); for (Query query : queries) { FutureResult future executor.submit(() - { try (var statement connection.prepareStatement(query.sql())) { // 执行查询 return executeQuery(statement); } }); futures.add(future); } // 收集结果 ListResult results new ArrayList(); for (FutureResult future : futures) { results.add(future.get()); } } catch (Exception e) { throw new ProcessingException(Failed to process queries, e); } } }五、Spring Boot 中的虚拟线程1. 启用虚拟线程spring: threads: virtual: enabled: true2. 自定义虚拟线程执行器Configuration public class VirtualThreadConfig { Bean(name virtualThreadExecutor) public Executor virtualThreadExecutor() { ThreadFactory factory Thread.ofVirtual() .name(virtual-thread-, 0) .factory(); return Executors.newThreadPerTaskExecutor(factory); } Bean public TomcatProtocolHandlerCustomizer? protocolHandlerVirtualThreadExecutorCustomizer() { return protocolHandler - { protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); }; } }3. 异步方法使用虚拟线程Service public class AsyncUserService { Async(virtualThreadExecutor) public CompletableFutureUser fetchUserAsync(String userId) { // 这个方法会在虚拟线程中执行 User user userRepository.findById(userId) .orElseThrow(() - new UserNotFoundException(userId)); return CompletableFuture.completedFuture(user); } Async(virtualThreadExecutor) public CompletableFutureListOrder fetchUserOrdersAsync(String userId) { ListOrder orders orderRepository.findByUserId(userId); return CompletableFuture.completedFuture(orders); } }六、实践案例高并发 Web 服务场景描述构建一个高并发的用户服务需要处理大量并发请求。实现方案SpringBootApplication public class HighConcurrencyApplication { public static void main(String[] args) { SpringApplication.run(HighConcurrencyApplication.class, args); } } RestController RequestMapping(/api/users) public class UserController { Autowired private UserService userService; GetMapping(/{userId}) public User getUser(PathVariable String userId) { return userService.getUser(userId); } GetMapping(/{userId}/details) public UserDetails getUserDetails(PathVariable String userId) { return userService.getUserDetails(userId); } } Service public class UserService { Autowired private UserRepository userRepository; Autowired private OrderServiceClient orderServiceClient; Autowired private InventoryServiceClient inventoryServiceClient; public User getUser(String userId) { return userRepository.findById(userId) .orElseThrow(() - new UserNotFoundException(userId)); } public UserDetails getUserDetails(String userId) { // 并行获取用户信息、订单信息和库存信息 try (var scope new StructuredTaskScope.ShutdownOnFailure()) { FutureUser userFuture scope.fork(() - getUser(userId)); FutureListOrder ordersFuture scope.fork(() - orderServiceClient.getUserOrders(userId)); FutureInventoryStatus inventoryFuture scope.fork(() - inventoryServiceClient.getUserInventory(userId)); scope.join(); scope.throwIfFailed(); return new UserDetails( userFuture.resultNow(), ordersFuture.resultNow(), inventoryFuture.resultNow() ); } catch (Exception e) { throw new UserServiceException(Failed to get user details, e); } } }性能测试使用虚拟线程后系统可以轻松处理数万个并发连接而内存占用保持在较低水平。七、常见陷阱与避免方法1. 避免在虚拟线程中使用 ThreadLocal// 不推荐 private static final ThreadLocalRequestContext context new ThreadLocal(); // 推荐使用 ScopedValue private static final ScopedValueRequestContext context ScopedValue.newInstance();2. 避免长时间占用锁// 不推荐 public synchronized void longOperation() { // 长时间操作会钉住载体线程 Thread.sleep(Duration.ofMinutes(5)); } // 推荐使用非阻塞方式 public void betterLongOperation() { // 分段处理避免长时间持有锁 processInChunks(); }3. 注意数据库连接池配置spring: datasource: hikari: # 虚拟线程下可以配置更大的连接池 maximum-pool-size: 100 minimum-idle: 20 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000八、总结与建议虚拟线程是 Java 并发编程的重大突破它让高并发编程变得更加简单。以下是一些关键建议拥抱虚拟线程在 IO 密集型应用中优先使用虚拟线程避免钉住线程避免使用 synchronized 和 ThreadLocal合理配置资源根据虚拟线程特性调整连接池等配置充分测试确保应用在虚拟线程下正常工作这其实可以更优雅一点通过结合结构化并发和虚拟线程我们可以构建出既高效又易维护的并发程序。希望这篇文章能帮助你掌握 Java 虚拟线程的并发最佳实践。欢迎在评论区分享你的使用经验

相关文章:

Java 虚拟线程并发最佳实践:高并发编程新范式

Java 虚拟线程并发最佳实践:高并发编程新范式今天我们来聊聊 Java 虚拟线程的并发最佳实践,这是 Java 21 带来的革命性特性。一、虚拟线程概述 虚拟线程(Virtual Threads)是 Java 21 引入的轻量级线程实现,它彻底改变了…...

OpenClaw压力测试:Qwen3.5-9B持续工作24小时稳定性报告

OpenClaw压力测试:Qwen3.5-9B持续工作24小时稳定性报告 1. 测试背景与目标 上周在部署OpenClaw对接本地Qwen3.5-9B模型后,我产生了一个疑问:这套组合在长时间运行场景下表现如何?作为个人自动化工具,能否稳定处理周期…...

OpenClaw配置备份技巧:Kimi-VL-A3B-Thinking模型参数迁移无忧方案

OpenClaw配置备份技巧:Kimi-VL-A3B-Thinking模型参数迁移无忧方案 1. 为什么需要OpenClaw配置备份 上周我在升级主力开发机时,差点因为硬盘故障丢失了精心调校的OpenClaw配置。这个教训让我意识到,对于依赖本地AI助手的开发者来说&#xff…...

Java 微服务弹性模式:构建高可用分布式系统

Java 微服务弹性模式:构建高可用分布式系统今天我们来聊聊 Java 微服务中的弹性模式,这是构建高可用分布式系统的核心能力。一、为什么需要弹性模式 在分布式系统中,故障是不可避免的。网络延迟、服务宕机、资源耗尽等问题随时可能发生。如果…...

文脉定序系统Docker容器化部署与ComfyUI工作流集成

文脉定序系统Docker容器化部署与ComfyUI工作流集成 你是不是也遇到过这样的烦恼?手里有一堆文本素材,比如产品描述、用户评论或者文章草稿,想要把它们按照某种逻辑重新排列,让内容读起来更通顺、更有条理。手动整理吧&#xff0c…...

FireRedASR-AED-L环境配置:CUDA 11.8 + PyTorch 2.1.2 + Transformers 4.41一键集成

FireRedASR-AED-L环境配置:CUDA 11.8 PyTorch 2.1.2 Transformers 4.41一键集成 1. 项目简介 FireRedASR-AED-L是一个基于1.1B参数大模型开发的本地语音识别工具,专为中文、方言和中英混合语音识别而设计。这个工具最大的特点是完全本地运行&#xf…...

Youtu-Parsing保姆级部署指南:WebUI界面详解与常见问题解决

Youtu-Parsing保姆级部署指南:WebUI界面详解与常见问题解决 1. 项目简介与核心能力 Youtu-Parsing是腾讯优图实验室推出的专业文档解析模型,基于Youtu-LLM-2B构建,能够智能识别文档中的多种元素并进行结构化输出。这个模型特别适合需要处理…...

Windows下OpenClaw安装指南:Qwen3.5-9B-AWQ-4bit接口调用全流程

Windows下OpenClaw安装指南:Qwen3.5-9B-AWQ-4bit接口调用全流程 1. 为什么选择OpenClawQwen3.5组合 去年我在处理一个爬虫项目时,每天要重复执行几十次相同的命令行操作。直到发现OpenClaw这个能通过自然语言控制电脑的AI智能体,配合本地部…...

卡证检测矫正模型效果对比:矫正前后OCR字符识别准确率提升数据

卡证检测矫正模型效果对比:矫正前后OCR字符识别准确率提升数据 1. 引言:为什么卡证矫正如此重要? 想象一下这个场景:你用手机拍了一张身份证照片,准备上传到某个App里。照片拍得有点歪,身份证的四个角在画…...

AI绘画工作流:OpenClaw+Phi-3-vision-128k-instruct实现提示词自动优化

AI绘画工作流:OpenClawPhi-3-vision-128k-instruct实现提示词自动优化 1. 为什么需要自动化提示词优化 作为一名长期使用Stable Diffusion进行创作的数字艺术家,我发现自己每天要花费大量时间在提示词(prompt)的调试上。有时候为…...

电机模型、电流环PI控制器、PLL锁相环的标幺化处理及采样时间详解

电机标幺化、PI标幺化、锁相环PLL标幺化 详解电机模型相关标幺化处理 电流环PI控制器的标幺化处理 观测器中PLL锁相环的标幺化处理 采样时间处理 这是文档,不是代码,文档中的代码均为引用举例子的在电机控制的世界里,标幺化处理是一个绕不开的…...

7.ARP 代理与端口隔离:满足通信需求,保证通信安全

所谓ARP代理就是网络设备代替目标设备回应 ARP 请求 ,将自身 MAC 地址提供给请求方,以此满足了不同子网、VLAN 内及 VLAN 间设备的通信需求,在不同网络区域间搭建起通信桥梁。同时,它通过隐藏内部网络结构、限制广播域范围&#x…...

Go Context 生命周期控制逻辑解析

Go语言中的Context是控制并发任务生命周期的核心机制,它像一根隐形的线,贯穿于Goroutine的创建、执行和终止全过程。本文将深入解析Context如何通过精巧的设计实现超时控制、级联取消和数据传递,帮助开发者构建更健壮的分布式系统。理解其生命…...

【教学类-160-02】20260409 AI视频培训-练习2“豆包AI视频《小班-抢玩具》+豆包图片风格:手办”

背景需求: 【教学类-160-01】20260408 AI视频培训-练习1“豆包AI视频”https://mp.csdn.net/mp_blog/creation/editor/159965108 不是前面孩子的衣服了,从两女变成一男一女了 详细的人物特征描述(衣服颜色等)控制人物尽量相似。 …...

Retinaface+CurricularFace人脸识别镜像实测:5分钟快速部署,小白也能轻松上手

RetinafaceCurricularFace人脸识别镜像实测:5分钟快速部署,小白也能轻松上手 1. 为什么选择这个镜像? 想快速搭建一个高精度的人脸识别系统?市面上方案虽多,但要么部署复杂,要么效果不佳。今天给大家介绍…...

UEFI固件镜像解析:从FD到Section的逐层拆解

1. UEFI固件镜像解析入门指南 第一次拿到UEFI固件镜像时,很多人都会觉得无从下手。这个看似普通的二进制文件,实际上包含了计算机启动所需的所有关键代码。就像解剖人体需要了解骨骼结构一样,解析UEFI固件也需要先掌握它的层级架构。 我刚开始…...

3步打造专属邮件工作站:Gmail桌面版高效配置指南

3步打造专属邮件工作站:Gmail桌面版高效配置指南 【免费下载链接】gmail-desktop :postbox: Gmail desktop app for macOS, Windows & Linux (formerly Gmail Desktop) 项目地址: https://gitcode.com/gh_mirrors/gm/gmail-desktop 价值定位篇&#xff1…...

Qwen2.5-7B-Instruct快速上手:Docker环境搭建与模型加载

Qwen2.5-7B-Instruct快速上手:Docker环境搭建与模型加载 1. 引言 在当今AI技术快速发展的背景下,大语言模型已成为各行各业的重要工具。Qwen2.5-7B-Instruct作为阿里通义千问系列的最新旗舰模型,凭借其70亿参数的强大能力,在逻辑…...

AI写论文哪家强?这4款AI论文生成工具测评结果告诉你答案!

你是否还在为撰写期刊论文、毕业论文或职称论文而感到焦虑呢?在进行人工撰写时,面对海量的文献就像在浩瀚的大海中捞针,而繁琐的格式要求更是让人头疼,反复修改的过程常常让我们的耐心耗尽,低效率的写作成为众多学术研…...

MiniCPM-V-2_6数据中心:机柜图识别+温控与负载均衡建议

MiniCPM-V-2_6数据中心:机柜图识别温控与负载均衡建议 1. 项目背景与价值 在现代数据中心运维中,机柜设备识别和温度监控是两项关键任务。传统方法需要人工巡检和手动记录,效率低下且容易出错。MiniCPM-V-2_6作为先进的视觉多模态模型&…...

零基础转型AI产品经理?这份7阶段学习全攻略,助你少走两年弯路,抢占未来高薪岗位!

在AI浪潮席卷全球的今天,越来越多的人开始意识到:AI产品经理,将是未来最具竞争力的岗位之一。尤其是随着大模型(LLM)技术的爆发,一场“技术产品”的革命正在悄然上演。 很多小伙伴私信我:零基础…...

Multisim与Phi-4-mini-reasoning联动:从理论计算到仿真验证的智能辅助

Multisim与Phi-4-mini-reasoning联动:从理论计算到仿真验证的智能辅助 1. 引言:电路设计的新范式 想象一下这样的场景:你正在设计一个增益为100的同相放大器,传统流程需要翻阅教材查找公式、手工计算电阻值、反复调整参数才能开…...

HowTo-易连EDI-EasyLink如何进行一键部署

在易连EDI-EasyLink里,项目开发完毕时,可以点击功能菜单“部署包”功能进行一键部署。首先“创建” 部署包,输入名称和备注。然后点击“打包”打包日志如果没有错误,即为打包完成。紧接着,点击”部署”此时&#xff0c…...

NEURAL MASK 与 Vue.js 打造交互式图像重构效果演示平台

NEURAL MASK 与 Vue.js 打造交互式图像重构效果演示平台 你有没有想过,一个强大的图像处理算法,如果只能通过命令行或者复杂的脚本调用,那它的价值是不是被大大限制了?对于很多开发者或者研究者来说,他们可能更希望有…...

3个革新方案:解决Steam创意工坊模组下载难题

3个革新方案:解决Steam创意工坊模组下载难题 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 开篇:当你第5次输错游戏ID时 你是否遇到过这样的场景&…...

NumPy 矩阵核心操作入门

乘法、加法、转置与广播机制入门解析 前言 NumPy 是 Python 生态中数值计算的基石库,而矩阵(数组)操作是线性代数、数据分析、机器学习等领域的核心基础。本文将系统梳理 NumPy 中最常用的矩阵操作,包含矩阵乘法、矩阵加法、转置矩…...

接触电阻波动10mΩ?医疗连接器导电性能的隐形红线

从事连接器工程整整10年,今天想跟医疗设备行业的各位同行,聊一个最容易被忽略、却最容易出大问题的细节——医疗连接器的接触电阻波动。相信很多做设备选型的工程师都有过这样的经历:选连接器时,盯着规格书上的初始接触电阻值看&a…...

滞回电压计算的误差来源与修正策略

滞回比较器的阈值与滞回电压计算,通常基于理想运放与理想元件模型,但实际电路中,运放非理想特性、元件参数误差、外部干扰等因素,会导致理论计算值与实际测量值存在偏差 —— 轻则影响抗干扰效果,重则导致电路阈值偏移…...

Android Jetpack Compose - 修饰符顺序的影响、Divider(分隔线)、DropdownMenu(下拉菜单)、NavigationBar(导航栏)

一、修饰符顺序的影响 红色背景区域:200 - 50 * 2 100 * 100 dp,点击区域:200 - 50 * 2 100 * 100 dp val context LocalContext.currentBox(Modifier.size(200.dp).padding(50.dp).background(Color.Red).clickable {Toast.makeText(cont…...

OpenClaw技能市场探秘:千问3.5-35B-A3B-FP8支持的10个实用技能

OpenClaw技能市场探秘:千问3.5-35B-A3B-FP8支持的10个实用技能 1. 当多模态模型遇见自动化工具 第一次在本地部署完OpenClaw时,我盯着那个简陋的命令行界面发呆——这个号称能自动化一切的工具,到底能帮我做什么?直到我发现了Cl…...