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

JDK-21虚拟线程使用

引入:

1. 虚拟线程是挂载到平台线程(载体线程)中去的,在遇到阻塞时,载体线程将会从阻塞的虚拟线程进行卸载,虚拟线程阻塞结束,载体线程会挂载到空闲的载体线程上。

2. 虚拟线程与平台线程相比,有轻量化特点,更小,支持的并发量更多。

3. 无需池化,直接即可创建,设计的目标就是避免池化。

坑点:
1. 任务中使用 synchronized 包裹的代码则遇到阻塞会进行无法释放虚拟线程。

创建虚拟线程的方式:

1.创建虚拟线程,并且指定一个Name

// 创建并启动一个虚拟线程 Thread vt = Thread.ofVirtual() .name("my-vt-", 0) // 可选:设置名称前缀和起始编号 .start(() -> { System.out.println("Running in virtual thread"); System.out.println("Is virtual: " + Thread.currentThread().isVirtual()); }); vt.join(); // 等待完成

2. 直接创建虚拟线程,书写任务逻辑

// 一行代码创建并启动 Thread vt = Thread.startVirtualThread(() -> { System.out.println("Hello from virtual thread!"); }); vt.join();

3. 提交的任务都创建一个虚拟线程(虚拟线程执行器)

// 每个提交的任务都会获得一个新的虚拟线程 try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { executor.submit(() -> { Thread.sleep(Duration.ofSeconds(1)); return i; }) } // try-with-resources 自动关闭,等待所有任务完成

拓展使用:
1. 使用Callable进行规划任务逻辑,使用虚拟线程执行器进行执行代码逻辑,汇总返回结果。

private static void virtualThread3() { System.out.println("创建virtualThread"); long start = System.currentTimeMillis(); List<Callable<String>> tasks = List.of( () -> { for (int i = 0; i < 100; i++) { System.out.println("任务1 正在被 [" + Thread.currentThread() + "] 执行"); } // ✅ 在这里打印,看看是谁在执行我 return callUserService(); }, () -> { for (int i = 0; i < 100; i++) { System.out.println("任务2 正在被 [" + Thread.currentThread() + "] 执行"); } return callUserService(); }, () -> { for (int i = 0; i < 100; i++) { System.out.println("任务3 正在被 [" + Thread.currentThread() + "] 执行"); } return callUserService(); } ); try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { List<Future<String>> futures = executor.invokeAll(tasks); futures.stream().forEach(System.out::println); futures.stream() .map(f -> { try { return f.get(); // 此时任务已完成,get() 不会阻塞 } catch (Exception e) { throw new CompletionException(e); } }) .toList(); } catch (Exception e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("Time taken: " + (end - start) / 1000 + " 秒"); System.out.println("CPU Cores: " + Runtime.getRuntime().availableProcessors()); }

2. 使用CompletableFuture 指定虚拟线程方式进行启动

private static void virtualThread5() { System.out.println("创建 virtualThread (CompletableFuture)"); long start = System.currentTimeMillis(); ExecutorService vtExecutor = Executors.newVirtualThreadPerTaskExecutor(); // 每个任务独立提交,返回 CompletableFuture CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> { for (int i = 0; i < 100; i++) System.out.println("任务1 [" + Thread.currentThread() + "]"); try { return callUserService(); } catch (InterruptedException e) { throw new RuntimeException(e); } }, vtExecutor); // <--- 指定虚拟线程执行器 CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> { for (int i = 0; i < 100; i++) System.out.println("任务2 [" + Thread.currentThread() + "]"); try { return callUserService(); } catch (InterruptedException e) { throw new RuntimeException(e); } }, vtExecutor); CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> { for (int i = 0; i < 100; i++) System.out.println("任务3 [" + Thread.currentThread() + "]"); try { return callUserService(); } catch (InterruptedException e) { throw new RuntimeException(e); } }, vtExecutor); try { // 等待所有任务完成并收集结果 List<String> results = CompletableFuture.allOf(f1, f2, f3) .thenApply(v -> List.of(f1.join(), f2.join(), f3.join())) .join(); // 主线程阻塞等待 System.out.println("Results: " + results); } finally { vtExecutor.close(); // try-with-resources 也可以,这里手动演示 } System.out.println("Time taken: " + (System.currentTimeMillis() - start) / 1000 + " 秒"); }

3. 配合信号量使用

private static void virtualThread4() throws RuntimeException { final Semaphore DB_LIMITER = new Semaphore(50); try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { //先拿锁 executor.submit(() -> { try { DB_LIMITER.acquire(); //业务逻辑xxx callUserService(); } catch (InterruptedException e) { //释放锁 DB_LIMITER.release(); } }); } }
http://www.cnnetsun.cn/news/4123519.html

相关文章:

  • Cortex-M3-STM32F1 开发:(四十六)ADC 实例 4 :单通道 ADC 过采样实例,使用 DMA,两种编程方式
  • 收藏夹里500个“稍后再看“吃灰?这款免费AI视频总结工具帮你3分钟榨干B站课程
  • gruf 健康检查集成:接入官方 gRPC 健康检查协议,让 Ruby 微服务秒过探针
  • S-mall-ssm 订单状态机设计:5种状态如何驱动电商订单的完整生命周期?
  • 你的macOS菜单栏为什么总是乱成一团?这个叫Ice的菜单栏管理工具给出了答案
  • 老Mac免费吃上macOS Sequoia:OpenCore Legacy Patcher从零到上手完整指南
  • 磁盘空间告急怎么办?免费开源Czkawka的14个清理工具,帮你找出重复文件、相似图片和空文件夹
  • 深入源码:THCalendarDatePicker 日历网格布局算法是如何工作的?
  • 老款Mac焕新三步走:用OpenCore Legacy Patcher免费升级最新macOS完整指南
  • DesktopAssistant打包发布实战:生成Windows安装程序与deb包的完整步骤
  • ZCode与DeepSeek集成指南:打造本地AI编程助手
  • Dtims CPB4612-LF 控制板
  • 对比评测:GifHub vs 其他 GitHub GIF 插件,谁才是评论区动图之王?
  • TypeScript-New-Handbook 新手教程:10 分钟理解静态类型检查的核心理念
  • TypeScript-New-Handbook 完全指南:微软官方 TypeScript 新手册,一篇读懂全貌
  • 磁盘清理工具免费推荐:开源 Czkawka,把重复文件与相似图片一次清干净
  • THCalendarDatePicker 手势交互揭秘:滑动切换月份与年份的 5 个实现细节
  • 基于SpringBoot+Vue的个性化音乐平台网站(源码+讲解视频+LW)
  • obs-shaderfilter扩展像素功能解析:轻松实现投影与边框的渲染技巧
  • 【软考信息安全】密码学考点“涮“明白!5张美食思维导图带你一锅端
  • 给 Copilot for Xcode 开发自定义工具:3 个实战案例,把 AI 助手调教成真正会干活的搭档
  • ECC 智能体钩子系统架构解析:如何为 AI 编码 Agent 装上“会记忆、能拦截、可审计“的行为护栏
  • 洛雪音乐音源怎么装最省心?免费无损音源合集实测导入指南
  • 免费通用设计字体 Morisawa BIZ UDGothic 上手教程:三步搞定下载、安装与排版
  • FIFA 23 修改器完整免费指南:从首条脚本到高阶模组,快速掌控生涯模式全细节
  • 微信聊天记录终极备份指南:用WeChatMsg免费导出HTML、Word、CSV与年度报告
  • ZoneMTA 智能退信处理:如何识别灰名单、拒收与 IP 拉黑
  • 小芯片运行模型时的资源边界
  • vue-star-rating 无障碍实践:用 screen-reader 插槽提升评分的可访问性
  • gruf 性能调优指南:线程池与服务器参数最佳实践