Spring Boot 中的虚拟线程

在本文中,我将讨论 Spring Boot 中的虚拟线程。

在这里插入图片描述

什么是虚拟线程?

虚拟线程作为 Java 中的一项功能引入,旨在简化并发性。 Virtual threads 是 轻量级的线程,由 Java Virtual Machine 而不是操作系统管理。它们被设计为易于使用且高效,为并发编程提供了比传统 Java 线程更简单的模型。

在这里插入图片描述

  • Lightweight :与传统线程相比,虚拟线程的重量更轻。它们由 JVM 管理,许多虚拟线程可以映射到较少数量的操作系统线程。
  • Concurrency :虚拟线程旨在通过更轻松地编写可扩展和响应式应用程序来简化并发编程。
  • Thread Pool :不需要显式管理线程池。 JVM 可以根据工作负载动态调整线程数量。

在这里插入图片描述

没有执行器的虚拟线程声明方式

public static void main(String[] args) {

    Thread virtualThread = Thread.ofVirtual().start(() -> {
        System.out.println("Virtual thread running");
    });

    System.out.println("Main thread running");    

}
private static void main(String[] args) {
        
        Thread virtualThread = Thread.ofVirtual()
                .name("Virtual Thread")
                .unstarted(() ->System.out.println("Virtual thread running"));
        
        t.start();
       
        try {
            virtualThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

Spring Boot 中的实现

Java Version: 20
Spring Version: 3.1.0

1) pom.xml

 <dependencies>

    <!--Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!--Prometheus, Zipkin & Micrometer-->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
        <scope>runtime</scope>
        <version>1.11.0</version>
    </dependency>

    <dependency>
        <groupId>io.zipkin.reporter2</groupId>
        <artifactId>zipkin-reporter-brave</artifactId>
        <version>2.16.3</version>
    </dependency>

    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-tracing-bridge-brave</artifactId>
    </dependency>

    <!--Actuator & AOP-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        <version>3.1.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
  
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>20</source>
                <target>20</target>
                <compilerArgs>
                    --enable-preview
                </compilerArgs>
            </configuration>
        </plugin>
  
    </plugins>
</build>

必须确保有 Java 21 的 JVM 可用! (如果您运行的是 Java 19,则可以使用 --preview-enabled=true 运行虚拟线程。)

2) application.properties

spring.application.name=spring-vthread-service

management.zipkin.tracing.endpoint=http://${ZIPKIN_HOST:localhost}:9411/api/v2/spans
management.tracing.sampling.probability=1.0
management.endpoints.web.exposure.include=info,health,prometheus,metrics
server.tomcat.mbeanregistry.enabled=true
management.metrics.tags.application=${spring.application.name}

logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]

3)VThreadServiceApplication

1、创建100_000个传统Java线程并执行。
@SpringBootApplication
public class VThreadServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(VThreadServiceApplication.class, args);
    }

    @Bean
    public ApplicationRunner runner() {

        return args -> {
            var startDate = Instant.now();

            startThreads();

            var finishDate = Instant.now();
            System.out.println(String.format("Start Date: %s, Finish Date: %s", startDate, finishDate));
            System.out.println(String.format("Duration Time(Milliseconds): %s", Duration.between(startDate, finishDate).toMillis()));

        };
    }

    private void startThreads() throws InterruptedException {

        for (int i = 0; i < 100_000; i++) {
            int finalI = i;
            Thread t = new Thread(() -> System.out.println(finalI));
            t.start();
            t.join();
        }
    }

}

输出:

 .
 .
99998
99999
Start Date: 2023-11-18T12:20:09.491114200Z, Finish Date: 2023-11-18T12:20:28.139291800Z
Duration Time(Milliseconds): 18648

Duration Time(Milliseconds): 18648

CPU使用率:

在这里插入图片描述

2.、创建100_000个虚拟Java线程并执行。

@SpringBootApplication
public class VThreadServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(VThreadServiceApplication.class, args);
    }

    @Bean
    public ApplicationRunner runner() {

        return args -> {
            var startDate = Instant.now();

            startVirtualThreads();

            var finishDate = Instant.now();
            System.out.println(String.format("Start Date: %s, Finish Date: %s", startDate, finishDate));
            System.out.println(String.format("Duration Time(Milliseconds): %s", Duration.between(startDate, finishDate).toMillis()));

        };
    }

    private void startVirtualThreads() throws InterruptedException {

        for (int i = 0; i < 100_000; i++) {
            int finalI = i;
            Thread t = Thread.ofVirtual()
                    .name(String.format("virtualThread-%s", i))
                    .unstarted(() -> System.out.println(finalI));
            t.start();
            t.join();

        }
    }

}

输出:

.
  .
99998
99999
Start Date: 2023-11-18T12:22:14.838308900Z, Finish Date: 2023-11-18T12:22:18.588181800Z
Duration Time(Milliseconds): 3749

Duration Time(Milliseconds): 3749

CPU使用率:

在这里插入图片描述

3. 创建Http控制器
@RestController
@RequestMapping("/api/v1/threads")
@Slf4j
public class ThreadController {

    @GetMapping("")
    public String thread() throws InterruptedException {
        Thread.sleep(1000);
        var threadName = Thread.currentThread().toString();
        log.info(threadName);
        return "thread executed";
    }

}
3.1 发送HTTP请求(传统线程)

发送 1600 请求。
并发请求数:400

命令

ab -n 1600 -c 400 host.docker.internal:8080/api/v1/threads

Response Summary

This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking host.docker.internal (be patient)
Completed 160 requests
Completed 320 requests
Completed 480 requests
Completed 640 requests
Completed 800 requests
Completed 960 requests
Completed 1120 requests
Completed 1280 requests
Completed 1440 requests
Completed 1600 requests
Finished 1600 requests


Server Software:
Server Hostname:        host.docker.internal
Server Port:            8080

Document Path:          /api/v1/threads
Document Length:        15 bytes

Concurrency Level:      400
Time taken for tests:   9.659 seconds
Complete requests:      1600
Failed requests:        0
Total transferred:      236800 bytes
HTML transferred:       24000 bytes
Requests per second:    165.65 [#/sec] (mean)
Time per request:       2414.722 [ms] (mean)
Time per request:       6.037 [ms] (mean, across all concurrent requests)
Transfer rate:          23.94 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        2  127  51.4    118     375
Processing:  1040 1877 258.2   1905    2438
Waiting:     1010 1755 257.0   1781    2304
Total:       1042 2004 268.9   2019    2660

Percentage of the requests served within a certain time (ms)
  50%   2019
  66%   2032
  75%   2041
  80%   2048
  90%   2540
  95%   2603
  98%   2638
  99%   2650
 100%   2660 (longest request)

Time taken for tests :9.659 秒

3.2发送HTTP请求(虚拟线程)

创建线程执行器
线程执行器配置

@Configuration
@Slf4j
public class ThreadExecutorConfig {

    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
        return protocolHandler -> {
            log.info("Configuring " + protocolHandler + " to use VirtualThreadPerTaskExecutor");
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
        };
    }

}

发送 1600 请求。
并发请求数:400

Command 命令

ab -n 1600 -c 400 host.docker.internal:8080/api/v1/threads

Response Summary

This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking host.docker.internal (be patient)
Completed 160 requests
Completed 320 requests
Completed 480 requests
Completed 640 requests
Completed 800 requests
Completed 960 requests
Completed 1120 requests
Completed 1280 requests
Completed 1440 requests
Completed 1600 requests
Finished 1600 requests


Server Software:
Server Hostname:        host.docker.internal
Server Port:            8080

Document Path:          /api/v1/threads
Document Length:        0 bytes

Concurrency Level:      400
Time taken for tests:   7.912 seconds
Complete requests:      1600
Failed requests:        0
Total transferred:      211200 bytes
HTML transferred:       0 bytes
Requests per second:    202.22 [#/sec] (mean)
Time per request:       1978.077 [ms] (mean)
Time per request:       4.945 [ms] (mean, across all concurrent requests)
Transfer rate:          26.07 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1  186  89.6    197     337
Processing:  1005 1376 251.1   1423    1855
Waiting:     1005 1198 158.2   1171    1591
Total:       1040 1562 244.2   1612    2060

Percentage of the requests served within a certain time (ms)
  50%   1612
  66%   1668
  75%   1691
  80%   1724
  90%   1903
  95%   1997
  98%   2037
  99%   2048
 100%   2060 (longest request)

Time taken for tests :7.912 秒

相关文档:

  • 三 分钟理解 Java 虚拟线程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/274408.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Apache Flink连载(十八):Flink On Yarn运行原理及环境准备

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录 1. Flink On Yarn运行原理…

Final Cut 视频剪辑快速入门,小白上手视频课的制作

本文是一个快速入门教程&#xff0c;如果您是0视频处理基础&#xff0c;又想录制网课或是一些对效果要求不高的视频那么这篇教程足够使用了。 本文主要用Final Cut处理视频课&#xff0c;本文是笔者在制作视频课过程中逐渐摸索的&#xff0c;如果您想制作一些比较专业的视频&a…

docker学习(二十一、network使用示例container、自定义)

文章目录 一、container应用示例1.需要共用同一个端口的服务&#xff0c;不适用container方式2.可用示例3.停掉共享源的容器&#xff0c;其他容器只有本地回环lo地址 总结 二、自定义网络应用示例默认bridge&#xff0c;容器间ip通信默认bridge&#xff0c;容器间服务名不通 自…

SpringBoot 3.2.0 基于Logback定制日志框架

依赖版本 JDK 17 Spring Boot 3.2.0 工程源码&#xff1a;Gitee 日志门面和日志实现 日志门面&#xff08;如Slf4j&#xff09;就是一个标准&#xff0c;同JDBC一样来制定“规则”&#xff0c;把不同的日志系统的实现进行了具体的抽象化&#xff0c;只提供了统一的日志使用接…

C语言实验1:C程序的运行环境和运行C程序的方法

一、算法原理 这是学C语言的入门&#xff0c;并不需要很高深的知识&#xff0c;一个hello world 或者一个简单的加法即可 二、实验要求 了解所用的计算机系统的基本操作方法&#xff0c;学会独立使用该系统。 了解在该系统上如何编辑、编译、连接和运行一个C程序。 通过运…

Kali Linux如何启动SSH并在Windows系统远程连接

文章目录 1. 启动kali ssh 服务2. kali 安装cpolar 内网穿透3. 配置kali ssh公网地址4. 远程连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 简单几步通过[cpolar 内网穿透](cpolar官网-安全的内网穿透工具 | 无需公网ip | 远程访问 | 搭建网站)软件实现ssh 远程连接kali! …

PyTorch实战:基于Seq2seq模型处理机器翻译任务(模型预测)

文章目录 引言数据预处理加载字典对象en2id和zh2id文本分词 加载训练好的Seq2Seq模型模型预测完整代码结束语 引言 随着全球化的深入&#xff0c;翻译需求日益增长。传统的人工翻译方式虽然质量高&#xff0c;但效率低&#xff0c;成本高。机器翻译的出现&#xff0c;为解决这…

八股文打卡day12——计算机网络(12)

面试题&#xff1a;HTTPS的工作原理&#xff1f;HTTPS是怎么建立连接的&#xff1f; 我的回答&#xff1a; 1.客户端向服务器发起请求&#xff0c;请求建立连接。 2.服务器收到请求之后&#xff0c;向客户端发送其SSL证书&#xff0c;这个证书包含服务器的公钥和一些其他信息…

Python 网络编程之搭建简易服务器和客户端

用Python搭建简易的CS架构并通信 文章目录 用Python搭建简易的CS架构并通信前言一、基本结构二、代码编写1.服务器端2.客户端 三、效果展示总结 前言 本文主要是用Python写一个CS架构的东西&#xff0c;包括服务器和客户端。程序运行后在客户端输入消息&#xff0c;服务器端会…

文件操作安全之-目录穿越流量告警运营分析篇

本文从目录穿越的定义,目录穿越的多种编码流量数据包示例,目录穿越的suricata规则,目录穿越的告警分析研判,目录穿越的处置建议等几个方面阐述如何通过IDS/NDR,态势感知等流量平台的目录穿越类型的告警的线索,开展日常安全运营工作,从而挖掘有意义的安全事件。 目录穿越…

Quartus的Signal Tap II的使用技巧

概述&#xff1a; Signal Tap II全称Signal Tap II Logic Analyzer&#xff0c;是第二代系统级调试工具&#xff0c;它集成在Quartus II软件中&#xff0c;可以捕获和显示实时信号&#xff0c;是一款功能强大、极具实用性的FPGA片上调试工具软件。 传统的FPGA板级调试是由外接…

TCP的三次握手

TCP 是一种面向连接的单播协议&#xff0c;在发送数据前&#xff0c;通信双方必须在彼此间建立一条连接。所谓的“连接”&#xff0c;其实是客户端和服务器的内存里保存的一份关于对方的信息&#xff0c;如 IP 地址、端口号等。 TCP 可以看成是一种字节流&#xff0c;它…

《Spring Cloud学习笔记:微服务保护Sentinel》

Review 解决了服务拆分之后的服务治理问题&#xff1a;Nacos解决了服务治理问题OpenFeign解决了服务之间的远程调用问题网关与前端进行交互&#xff0c;基于网关的过滤器解决了登录校验的问题 流量控制&#xff1a;避免因为突发流量而导致的服务宕机。 隔离和降级&#xff1a…

hadoop hive spark flink 安装

下载地址 Index of /dist ubuntu安装hadoop集群 准备 IP地址主机名称192.168.1.21node1192.168.1.22node2192.168.1.23node3 上传 hadoop-3.3.5.tar.gz、jdk-8u391-linux-x64.tar.gz JDK环境 node1、node2、node3三个节点 解压 tar -zxvf jdk-8u391-linux-x64.tar.gz…

苹果cmsV10蜘蛛统计插件+集合采集插件

苹果cmsV10蜘蛛统计插件集合采集插件 安装苹果cms盒子方法&#xff1a; 1.下载到的盒子客户端压缩包内拥有一个application文件夹&#xff0c;直接上传到网站根目录中。 2.添加苹果cms盒子快捷菜单&#xff1a;苹果cms盒子,macBox/stylelist 相信做网站的都想要百度 搜狗 3…

RabbitMQ 和 Kafka 对比

本文对RabbitMQ 和 Kafka 进行下比较 文章目录 前言RabbitMQ架构队列消费队列生产 Kafka本文小结 前言 开源社区有好多优秀的队列中间件&#xff0c;比如RabbitMQ和Kafka&#xff0c;每个队列都貌似有其特性&#xff0c;在进行工程选择时&#xff0c;往往眼花缭乱&#xff0c;不…

浅谈WPF之ToolTip工具提示

在日常应用中&#xff0c;当鼠标放置在某些控件上时&#xff0c;都会有相应的信息提示&#xff0c;从软件易用性上来说&#xff0c;这是一个非常友好的功能设计。那在WPF中&#xff0c;如何进行控件信息提示呢&#xff1f;这就是本文需要介绍的ToolTip【工具提示】内容&#xf…

【INTEL(ALTERA)】如何使用Tcl打开quartus IP自带的例程

前言 很多INTEL&#xff08;ALTERA&#xff09; IP生成的时候会自带例程&#xff0c;如LVDS SERDES IP&#xff0c;在菜单Generate中可以选择生成官方例程。 之后会在IP所在目录下生产【lvds_0_example_design】文件夹&#xff0c;但在这个文件夹中并没有FPGA工程。 例程在哪&…

【Linux】 last 命令使用

last 命令 用于检索和展示系统中用户的登录信息。它从/var/log/wtmp文件中读取记录&#xff0c;并将登录信息按时间顺序列出。 著者 Miquel van Smoorenburg 语法 last [-R] [-num] [ -n num ] [-adiox] [ -f file ] [name...] [tty...]last 命令 -Linux手册页 选项及作用…

Flask登陆后登陆状态及密码的修改和处理

web/templates/common 是统一布局 登录成功 后flask框架服务器默认由login.html进入仪表盘页面index.html(/),该页面的设置在 (web/controllers/user/index.py)&#xff0c;如果想在 该仪表盘页面 将 用户信息 展示出来&#xff0c;就得想办法先获取到 当前用户的 登陆状态。…