文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

虚拟线程在Spring Boot中的应用及性能对比

2024-11-29 18:15

关注

1. 简介

在本篇文章中,我们将学习如何在Spring Boot应用程序中利用虚拟线程的强大功能。

虚拟线程由Project Loom引入,并在Java 19中作为预览功能提供,并且在成为官方JDK 21版本的一部分。此外,Spring 6版本集成了这一强大功能,允许开发者进行尝试。

首先,我们将了解“平台线程”与“虚拟线程”之间的主要区别。接下来,我们将从头开始构建一个使用虚拟线程的Spring Boot应用程序。最后,我们将创建一个小型测试,以检查简单Web应用的吞吐量是否有所提升。

虚拟线程 VS. 平台线程

主要区别在于,虚拟线程在运行周期内不依赖操作系统线程。虚拟线程与硬件解耦,因此称为 "虚拟"。此外,JVM 提供的抽象层赋予了这种解耦。

在本文中,我们要验证虚拟线程的运行成本远低于平台线程。我们要确认,创建数百万个虚拟线程不会出现内存不足错误(平台线程容易出现此问题)。

关于虚拟线程的详细介绍,可查看下面这篇文章

提升系统吞吐量,详解JDK21虚拟线程,炸裂

2. 实战案例

2.1 开启虚拟线程支持

从 Spring Boot 3.2 开始,如果我们使用 Java 21,启用虚拟线程非常简单。我们将 spring.threads.virtual.enabled 属性设置为 true,然后就可以开始了:

spring:
  threads:
    virtual:
      enabled: true

理论上,我们不需要做其他任何事情。但是,从普通线程切换到虚拟线程可能会给传统应用程序带来不可预见的后果。因此,我们必须对应用程序进行全面测试。

2.2 验证虚拟线程

通过上面开启虚拟线程后,我们通过如下方式是否正确的开启了虚拟线程。

@GetMapping("name")
public String toThread() {
  return Thread.currentThread().toString() ;
}

这里我们打印当前处理请求的线程名称,输出结果:

图片

响应结果明确指出我们正在使用虚拟线程处理此网络请求。换句话说,Thread.currentThread() 调用返回了 VirtualThread 类的一个实例。

2.3 性能对比

为了比较性能,我们将使用 JMeter 运行负载测试。这并不是一个完整的性能比较,而是一个起点,我们可以从这个起点出发,用不同的参数建立更多的测试。

在这个特定场景中,我们将通过Controller接口进行测试,该接口只需让执行进入休眠状态一秒钟,模拟一个复杂的异步任务:

@RestController
@RequestMapping("/load")
public class LoadTestController {


  private static final Logger logger = LoggerFactory.getLogger(LoadTestController.class) ;


  @GetMapping
  public void test() throws InterruptedException {
      logger.info("日志信息...") ;
      // 模拟耗时操作
      Thread.sleep(1000) ;
  }
}

接下来,在JMeter中创建一个线程组,模拟 1000 个并发用户在 100 秒内访问 /load 接口:

图片

在这种情况下,采用这项新功能所带来的性能提升是显而易见的。让我们比较一下不同实现的 "响应时间图"。这是标准线程的响应时间图。我们可以看到,完成一次调用所需的时间很快就达到了 5000 毫秒:

图片

这种情况发生是因为平台线程是一种有限资源。当所有计划的和池中的线程都在忙碌时,Spring 应用程序只能等待,直到有一个线程空闲下来,才能处理该请求。

接下来,使用虚拟线程进行测试

图片

生成的图表显示,响应时间稳定在1000毫秒。因此,从资源消耗的角度来看,虚拟线程非常高效,请求发出后会立即创建并使用它们。

这种性能提升仅在像我们的演示示例这样的简单场景中才可能实现。实际上,对于CPU密集型操作,虚拟线程并不合适,因为这类任务需要极少的阻塞。

下面,我们在通过一个需要CPU大量计算的操作进行测试,测试代码如下:

// 该示例计算大数的阶乘
@GetMapping("calc")
public String calc() {
  // 取值越大计算耗时就越高
  int number = 20000 ;
  // 开始时间
  long startTime = System.currentTimeMillis();
  System.out.println("开始时间: " + new Date(startTime));
  // 执行耗时计算
  factorial(number);
  // 结束时间
  long endTime = System.currentTimeMillis();
  System.out.println("结束时间: " + new Date(endTime));
  // 计算总耗时
  long duration = (endTime - startTime);
  return "计算" + number + "! 耗时: " + duration + " 毫秒" ;
}
private static BigInteger factorial(int n) {
  BigInteger result = BigInteger.ONE;
  for (int i = 1; i <= n; i++) {
    result = result.multiply(BigInteger.valueOf(i));
  }
  return result;
}

首先,是平台线程测试结果如下:

图片

如下,是虚拟线程测试结果

图片

根据这里的测试结果,发现他们的结果差不多。但虚拟线程似乎更加平稳吧。

来源:Spring全家桶实战案例源码内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯