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

【JDK21】详解虚拟线程

目录

1.概述

2.虚拟线程是为了解决哪些问题

2.1.线程切换的巨大代价

2.2.哪些情况会造成线程的切换

2.3.线程资源是有限的

3.虚拟线程

4.适用场景


1.概述

你发任你发,我用JAVA8?JDK21可能要对这句话say no了。

现在Oracle JDK是每4个版本,推出一个长期支持版本,JDK21就是前段时间发布的最新的长期支持版JDK。作为最新的长期支持版JDK,JDK21中集合了非常多的重要新特性,其中最为重要,最有意义,最吸引人的莫过于——虚拟线程。虚拟线程虽然不是JDK21才引入的,但是是在该版本中才得以稳定的,所以我们建议要用虚拟线程的话,最好还是使用JDK21。

本文将用一个清晰的思路抽丝剥茧,层层递进的去探讨:

1.虚拟线程是为了解决哪些问题

在虚拟线程出现之前,传统线程模型中线程切换存在的问题,即线程切换的代价。

然后去思考哪些情况下线程会切换?有哪些可以优化的地方?

2.虚拟线程是怎么解决这些问题的

然后是虚拟线程是怎样工作的?是怎样进行任务调度的?

3.虚拟线程的实际应用价值

虚拟线程的适用场景。

2.虚拟线程是为了解决哪些问题

2.1.线程切换的巨大代价

虚拟线程是为了解决哪些问题?自然是为了解决之前传统线程模型存在的一些问题。如果对计算机的线程模型不是很熟悉的同学博主之前有一篇文章,有兴趣可以看一下:

【进程与线程】最好懂的讲解-CSDN博客

所以传统的线程模型存在哪些问题喃?这就要从线程切换的巨大代价聊起。

先给出结论——线程的切换可能会引起CPU上下文的切换,从而造成巨大的CPU资源的浪费。接下来我们聊聊具体原因。

CPU的读写速率是要远远高于内存的读写速率的,为了配平CPU和内存之间速率的差距,CPU和内存之间存在着一个由寄存器组成的中间层,寄存器种会存放着CPU接下来要执行的指令,以及后续可能要执行到的指令以及可能要用到的数据。只有预先装载进去这部分可能要用到的东西才能抹平CPU和内存之间的速率差距,不然每次都要去内存取内容,可能是会拉低CPU的效率的。

但该预先装载哪些内容进寄存器种喃?这里遵循了程序的局部性原理。

程序的局部性原理:

程序在执行的时候呈现出局部性规律,在一段时间内,整个程序的执行仅限于程序中的某一个部分,相应的,执行所访问的存储空间也局限于某个内存区域。局部性又分为时间局部性和空间局部性。时间局部性指的是,如果程序中的某条指令一旦执行,则不久后可能会被再次执行,执行指令时访问的数据单元在不久后会被再次访问。空间局部性指的是,一旦访问了某个存储单元,不久后,其附近的存储单元也将被访问。

CPU上下文切换:

寄存器中存储着当前执行的指令、数据、以及下一条指令在内存中的地址等等事关程序正常运行的关键信息。所以寄存器中存储的内容合称为CPU的上下文。

线程切换就可能会存在这样的问题:CPU上下文中存放的是当前线程的要的东西,可能不是下个线程要用的东西。下个线程被执行的时候,可能CPU的上下文就要换一套。CPU上下文的内容本来就是来自于内存,也就是说切换上下文就是去内存中读取要的东西。CPU的读写速度是远远高于内存的读写速度的,在这个切换过程中CPU没啥事儿可干了,就会造成CPU的浪费。

2.2.哪些情况会造成线程的切换

前面我们已经说了线程切换的巨大代价,接下来我们就要想想,什么情况下线程会切换喃?常见的无非两种情况:

  1. 分给当前线程的时间片到了
  2. 线程阻塞了

我们分情况来讨论,首先是分给当前线程的时间片到了造成的线程切换。这类线程切换有问题吗?能被优化吗?很显然没问题,也不能去动它,因为进程和线程的出现本质上就是为了让多个程序能被交替执行,提升CPU的利用率,所以当前线程时间片到了,它就应该把CPU交出来,其它线程才有机会被执行。

至于第二种,线程阻塞引起的线程切换,就是值得我们进行优化的了。线程阻塞了,只是当前任务阻塞了,线程只是任务的载体,完全可以换个任务在上面继续执行。同理还有一种情况,就是时间片还没有用完,线程上面的任务跑完了,其实也该这样处理。

2.3.线程资源是有限的

除了上面线程切换的问题外,还有一点是值得注意的,就是线程资源是有限的,一台计算机上能开出来的线程是有上限的。

操作系统能够同时开启的线程数量是有限的主要有以下几个原因:

  1. 有限的系统资源:每个线程需要占用一定的系统资源,包括内存、CPU时间片、文件描述符等。系统的资源是有限的,因此开启过多的线程会消耗大量资源,可能导致资源耗尽或者性能下降。

  2. 调度开销:操作系统需要花费时间来管理和调度线程,包括线程的创建、销毁、切换等操作。如果线程数量过多,操作系统的调度开销会增加,降低系统的效率。

总结起来说人话就是,用来描述进程和线程的描述符(PCB或者TCP等)要存在内存中、内存是有限的,所以理论上线程自然是有上限的。

3.虚拟线程

前面罗嗦了这么多,总结起来无非就是计算机的线程资源是有限的,线程的切换会造成CPU资源的浪费。所以如果能复用线程资源,会提升多任务执行的效率。虚拟线程其实就是对线程资源的一种复用。

传统的JDK线程是每一条对应一条操作系统的线程,而虚拟线程是多个虚拟线程对应一条JDK的线程:

虚拟线程体系其实就是依赖于fork join pool来实现的,线程池中的每个JDK线程会对应一个任务列表,列表中会有多个虚拟线程,其实就是多个任务,由fork join pool的调度器来调度虚拟线程(任务)到各条平台线程上去。当有虚拟线程(任务)阻塞或者在时间片内提前执行完了等情况发生,调度器会去调度任务队列中的虚拟线程(任务)到这条平台线程上去继续执行:

ok,终于到虚拟线程的使用了,其实虚拟线程的使用本身反而还没有啥很多要说的。API的设计使用,当然是具有越极致的开闭性越好,所以作为线程的一个补充,虚拟线程的使用,在API层面是很简单的,和传统JDK线程的API语法几乎是一样的。

前置条件就不多说了,肯定是下载安装配置好JDK21,都在看JDK新特性的同学,这个肯定都是小问题,不赘述了。

手动开启虚拟线程:

Thread thread=Thread.ofVirtual().name("vittualThread").unstarted(new Task());
thread.start();

自动开启虚拟线程:

Thread thread=Thread.ofVirtual().name("virtualThread").start(new Task());

线程池:

ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
executorService.submit(new Task( ));
executorService.submit(new Task( ));
executorService.submit(new Task( ));

4.适用场景

虚拟线程采用协作式调度,线程主动放弃 CPU 控制权,而不是由操作系统强制切换。这种调度模型对于 IO 密集型任务非常适用,因为在等待 IO 操作完成的时候,线程可以主动让出 CPU 控制权,允许其他任务继续执行,提高了系统的吞吐量。

然而,在 CPU 密集型计算任务中,线程需要持续占用 CPU 资源进行计算,不适合频繁地放弃 CPU 控制权。虚拟线程的协作式调度可能导致任务在进行计算时频繁地让出 CPU,从而降低了计算密集型任务的执行效率。

虚拟线程对于IO密集型任务的友好,从tomcat11主动去拥抱JDK11,可见一斑:

tomcat作为一个web server,面对网络IO时,使出一手虚拟线程,毫无疑问可以大大拉高系统的吞吐量。

相关文章:

【JDK21】详解虚拟线程

目录 1.概述 2.虚拟线程是为了解决哪些问题 2.1.线程切换的巨大代价 2.2.哪些情况会造成线程的切换 2.3.线程资源是有限的 3.虚拟线程 4.适用场景 1.概述 你发任你发,我用JAVA8?JDK21可能要对这句话say no了。 现在Oracle JDK是每4个版本&#x…...

UE5 - 虚幻引擎各模块流程图

来自虚幻官方的一些资料,分享一下; 一些模块的流程图,比如动画模块: 或角色相关流程: 由于图片比较大,上传到了网络,可自取: 链接:https://pan.baidu.com/s/1BQ2KiuP08c…...

vue3实现element table缓存滚动条

背景 对于后台管理系统,数据的展示形式大多都是通过表格,常常会出现的一种场景,从表格跳到二级页面,再返回上一页时,需要缓存当前的页码和滚动条的位置,以为使用keep-alive就能实现这两种诉求,…...

flutter布局详解及代码示例(下)

布局 基本布局 GridView(二维滚动列表):比ListView多了一个方向的数据填充。ListBody(滚动列表):相比ListView,没有回收复用,简单易用。Table(表格布局)&am…...

SQL Server:流程控制语言详解

文章目录 一、批处理、脚本和变量局部变量和全局变量1、局部变量2、全局变量 二、顺序、分支和循环结构语句1、程序注释语句2、BEGIN┅END语句块3、IF┅ELSE语句4、CASE语句5、WHILE语句6、BREAK和CONTINUE语句BREAK语句CONTINUE语句 三、程序返回、屏幕显示等语句1、RETURN语句…...

2、用命令行编译Qt程序生成可执行文件exe

一、创建源文件 1、新建一个文件夹&#xff0c;并创建一个txt文件 2、重命名为main.cpp 3、在main.cpp中添加如下代码 #include <QApplication> #include <QDialog> #include <QLabel> int main(int argc, char *argv[]) { QApplication a(argc, argv); QDi…...

【追求卓越08】算法--排序算法

引导 今天开始介绍我们在工作中经常遇到的算法--排序。排序算法有很多&#xff0c;我们主要介绍以下几种&#xff1a; 冒泡排序 插入排序 选择排序 归并排序 快速排序 计数排序 基数排序 桶排序 我们需要了解每一种算法的定义以及实现方式&#xff0c;并且掌握如何评…...

Linux fork笔试练习题

1.打印结果&#xff1f; #include <stdio.h> #include <unistd.h> #include <stdlib.h>int main() {int i0;for(;i<2;i){fork();printf("A\n");}exit(0); } 结果打印 A A A A A A 2.将上面的打印的\n去掉,结果如何? printf("…...

Jenkins 整合 Docker 自动化部署

Docker 安装 Jenkins 配置自动化部署 1. Docker 安装 Jenkins 1.1 拉取镜像文件 docker pull jenkins/jenkins1.2 创建挂载文件目录 mkdir -p $HOME/jenkins_home1.3 启动容器 docker run -d -p 8080:8080 -v $HOME/jenkins_home:/var/jenkins_home --name jenkins jenkin…...

竞赛选题 题目:基于大数据的用户画像分析系统 数据分析 开题

文章目录 1 前言2 用户画像分析概述2.1 用户画像构建的相关技术2.2 标签体系2.3 标签优先级 3 实站 - 百货商场用户画像描述与价值分析3.1 数据格式3.2 数据预处理3.3 会员年龄构成3.4 订单占比 消费画像3.5 季度偏好画像3.6 会员用户画像与特征3.6.1 构建会员用户业务特征标签…...

selenium已知一个元素定位同级别的另一个元素

1.需求与实际情况 看下图来举例 &#xff08;1&#xff09;需求 想点击test22&#xff08;即序号-第9行&#xff09;这一行中右边的“复制”这一按钮 &#xff08;2&#xff09;实际情况 只能通过id或者class定位到文件名这一列的元素&#xff0c;而操作这一列的元素是不…...

Kotlin中 for in 是有序的吗?forEach呢?

我们要遍历一个数组、一个列表&#xff0c;经常会用到kotlin的 for in 语法&#xff0c;但是 for in 是不是有序的呢&#xff1f;forEach是不是有序的呢&#xff1f;这就需要看一下它们的本质了。 数组的 for in // 调用&#xff1a; val arr arrayOf(1, 2, 3) for (ele in …...

每日一练2023.11.27———连续因子【PTA】

题目链接&#xff1a;L1-006 连续因子​​​​​​​ 题目要求&#xff1a; 一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3567&#xff0c;其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N&#xff0c;要求编写程序求出最长连续因子的个数&#…...

P8A002-CIA安全模型-配置Linux描述网络安全CIA模型之可用性案例

【预备知识】 可用性(Availability) 数据可用性是一种以使用者为中心的设计概念,易用性设计的重点在于让产品的设计能够符合使用者的习惯与需求。以互联网网站的设计为例,希望让使用者在浏览的过程中不会产生压力或感到挫折,并能让使用者在使用网站功能时,能用最少的努力…...

SpringCloudAlibaba之sentinel 流量卫兵(流控,熔断降级) ——详细讲解

目录 一、什么是sentinel 二、sentinel使用 1. sentinel dashboard的安装 2.启动 3.访问web界面 ​编辑 4.登录 三、sentinel 实时监控服务 1.创建项目引入依赖 2.配置 3.启动服务 4.访问dashboard界面查看服务监控 5.开发服务 6.启动进行调用 7.查看监控界面 四、senti…...

C++封装dll和lib 供C++调用

头文件interface.h #pragma once #ifndef INTERFACE_H #define INTERFACE_H #define _CRT_SECURE_NO_WARNINGS #define FENGZHUANG_API _declspec(dllexport) #include <string> namespace FengZhuang {class FENGZHUANG_API IInterface {public:static IInterface* Cre…...

ffmpeg播放器实战(播放器流程)

1.流程图 1.main窗口创建程序窗口 程序窗口构造函数执行下面内容 2.开启播放 3.开启解码 4.开启渲染 5.反馈给ui 本文福利&#xff0c; 免费领取C音视频学习资料包学习路线大纲、技术视频/代码&#xff0c;内容包括&#xff08;音视频开发&#xff0c;面试题&#xff0c;FFmpeg…...

Android 13.0 开机过滤部分通知声音(莫名其妙的通知声音)

1.概述 在13.0的系统定制开发产品的中,有时候在系统开机的时候会有一些通知的声音,但是由于系统模块太多,也搞不清楚到底是哪个模块发出的通知声音,所以就需要从通知的流程来屏蔽这些通知声音,接下来看具体怎么实现在开机的时候过滤开机声音的功能 2.开机过滤部分通知声音…...

Adversarial Attack and Defense on Graph Data: A Survey(2022 IEEE Trans)

Adversarial Attack and Defense on Graph Data: A Survey----《图数据的对抗性攻击和防御&#xff1a;综述》 图对抗攻击论文数据库&#xff1a; https://github.com/safe-graph/graph-adversarial-learning-literature 摘要 深度神经网络&#xff08;DNN&#xff09;已广泛应…...

css中flex两列布局(一列自适应其他固定)

问题 最近写一个布局的时候&#xff0c;遇到一个问题。如下图的布局。在没有图片的时候布局是正常的&#xff0c;如果有图片且设置了width:100%;height: 100%; 则会出现图片将自适应布局撑开的情况。 我的解决方式是让图片不缩放&#xff0c;图片外层再添加一个div元素。形如…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...