JDK之8后: 协程? 虚拟线程!!!
特性官方文档: https://openjdk.org/jeps/436
Java协程
近三十年来,Java 开发人员一直依赖线程作为并发服务器应用程序的构建块。每个方法中的每个语句都在线程内执行,并且由于 Java 是多线程的,因此多个执行线程同时发生。线程是Java的并发单位:一段与其他此类单元同时运行且在很大程度上独立于其他此类单元的顺序代码。每个线程都提供一个堆栈来存储局部变量和协调方法调用,以及出错时的上下文:异常是由同一线程中的方法抛出和捕获的,因此开发人员可以使用线程的堆栈跟踪来找出发生了什么。线程也是工具的核心概念:调试器逐步执行线程方法中的语句,分析器可视化多个线程的行为以帮助了解它们的性能。
Why
thread-per-request 风格
- 每一个请求一个线程跟容易理解、易于编程、易于调试和分析;
- 线程很大程度决定了并发,但线程无法无限增长,线程的摧毁&建立&切换耗时长;
使用异步风格提高可扩展性
- IO操作更多的时候复用线程才能高效利用线程
- 颗粒度更小
- 但是处理一个请求使用多个线程交替-栈追踪不行&调试器不发处理
虚拟线程的含义
- 便宜又充足
- 不用被池化
- 创建线程的代价变小
- 虚拟线程保留了可靠的 thread-per-request 风格
- 非常适合IO密集型
案例代码
案例一
轻松创建10000个线程
- 如果使用传统方案创建10000个线程会大概率崩溃
- 协程每秒处理10000个任务
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {IntStream.range(0, 10_000).forEach(i -> {executor.submit(() -> {Thread.sleep(Duration.ofSeconds(1));return i;});});
} // executor.close() is called implicitly, and waits
案例二
io密集型的操作性能损耗更小,系统更加高效
void handle(Request request, Response response) {var url1 = ...var url2 = ...try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {var future1 = executor.submit(() -> fetchURL(url1));var future2 = executor.submit(() -> fetchURL(url2));response.send(future1.get() + future2.get());} catch (ExecutionException | InterruptedException e) {response.fail(e);}
}String fetchURL(URL url) throws IOException {try (var in = url.openStream()) {return new String(in.readAllBytes(), StandardCharsets.UTF_8);}
}
详解
独立的调度系统
线程需要被调度,即分配给在处理器内核上执行。对于作为操作系统线程实现的平台线程,JDK 依赖于操作系统中的调度程序。
虚拟线程,JDK 有自己的调度程序。JDK 的调度器不是直接将虚拟线程分配给处理器,而是将虚拟线程分配给平台线程,平台线程然后像往常一样由操作系统调度。
JDK 的虚拟线程调度程序是一种ForkJoinPool以 FIFO 模式运行的工作窃取。调度程序的并行度是可用于调度虚拟线程的平台线程数。默认情况下,它等于可用处理器的数量,但可以使用系统属性对其进行调整jdk.virtualThreadScheduler.parallelism。
也就是说,它默认并不是只基于一个线程,在一个线程上创建虚拟线程,而是处理器数量的基础线程数上创建虚拟线程
- 虽然可能在不同的线程但被屏蔽了
- 运行中获取的Thread.currentThread()始终是虚拟线程, 栈也与实际线程无关
执行虚拟线程
JDK 中的绝大多数阻塞操作都会卸载虚拟线程,释放它的载体和底层 OS 线程来承担新的工作。然而,JDK 中的一些阻塞操作并没有卸载虚拟线程,从而阻塞了它的载体和底层 OS 线程。这是因为操作系统级别(例如,许多文件系统操作)或 JDK 级别(例如,Object.wait())的限制。这些阻塞操作的实现将通过临时扩展调度程序的并行性来补偿操作系统线程的捕获。因此,调度程序中的平台线程数ForkJoinPool可能会暂时超过可用处理器的数量。可以使用系统属性调整调度程序可用的最大平台线程数jdk.virtualThreadScheduler.maxPoolSize。
有两种情况下虚拟线程无法在阻塞操作期间卸载,因为它被固定到其载体:
- 当它在块或方法内执行代码时synchronized,或者
- 当它执行一个native方法或一个外部函数时。
在案例中[10000次睡眠]执行结果可以预见的是不会阻塞或挂起线程,如果挂起线程可能就会出现睡眠10000秒的情况
也就是说这种阻塞操作会卸载虚拟线程(释放资源)执行其他;
也就是说有些操作会阻止虚拟线程的释放(不释放虚拟线程就会一直占用一个实际线程),从而导致虚拟线程的实际线程池超出上面说的核心数量, 比如调用native方法和Synchronized,;
初步测试下来wait&Synchronized是不会阻止卸载的
内存使用和与垃圾回收的交互
虚拟线程的堆栈作为堆栈块对象存储在 Java 的垃圾收集堆中。堆栈随着应用程序的运行而增长和收缩,既要提高内存效率,又要适应任意深度的堆栈(直到 JVM 配置的平台线程堆栈大小)。这种效率使大量虚拟线程成为可能,从而使服务器应用程序中每个请求线程样式的持续生存能力得以实现。
- 虚拟线程所需的栈帧布局比紧凑对象更浪费
- 虚拟线程不是GC根(也就是不是长活跃对象),所以只要没有被引用就会被回收
- 虚拟线程的堆栈达到区域大小的一半(可能小至 512KB),则StackOverflowError可能会抛出
核心: vs协程
核心区别
- 协程是基于一个线程,而虚拟线程是基于多个线程
- 虚拟线程需要注意多线程之间的同步&可见性问题, 协程基于单线程不需要注意
优势
基于多线程虽然要考虑多线的同步和可见性问题,但带了的是更高的性能水平
相关文章:
JDK之8后: 协程? 虚拟线程!!!
特性官方文档: https://openjdk.org/jeps/436 Java协程 近三十年来,Java 开发人员一直依赖线程作为并发服务器应用程序的构建块。每个方法中的每个语句都在线程内执行,并且由于 Java 是多线程的,因此多个执行线程同时发生。线程是Java的并发…...

体验 jeecg
体验 jeecg官网地址事前准备安装升级 node 和 npm 版本验证安装安装 pnpm clidocker 启动 MySQLdocker 启动 redisgit clone 项目启动JAVA项目 jeecg-boot启动Vue3项目 jeecgboot-vue3官网地址 http://www.jeecg.com/ 事前准备 (1) 为了回避Could not find artifact com.mic…...

投稿指南【NO.13】计算机学会CCF推荐期刊和会议分享(人工智能)
前 言国内高等院校研究生及博士毕业条件需要发表高水平期刊或者顶会(清北上交等重点学校毕业要求为至少发一篇顶会),很多同学私信问到一级学会的会议论文怎么找、是什么,比如前段时间放榜的CVPR论文就是人工智能领域的顶会国际会议…...

一份sql笔试
1、 select substr(time,1,10),count(order_id),count(distinct passenger_id) from order where substr(time,1,7)2023-08 group by substr(time,1,10) order by substr(time,1,10);2、 select city_id from (select * from order where substr(time,1,7) 2022-08) t1 left j…...
交换瓶子
交换瓶子 贡献者:programmer_ada 有N个瓶子,编号 1 ~ N,放在架子上。 比如有5个瓶子: 2 1 3 5 4 要求每次拿起2个瓶子,交换它们的位置。 经过若干次后,使得瓶子的序号为: 1 2 3 4 5 对于这么…...
二、Docker安装、启动、卸载、示例
Docker 支持 CentOS 6 及以后的版本,可以直接通过yum进行安装: 使用流程:启动主机 – 启动Docker服务 – 下载容器镜像 – 启动镜像得一个到容器 – 进入容器使用我们想要的程序 主机一般是Linux、Utuban 以下主机系统以CentOS7为例子&#…...

开心档之C++ STL 教程
C STL 教程 目录 C STL 教程 实例 在前面的章节中,我们已经学习了 C 模板的概念。C STL(标准模板库)是一套功能强大的 C 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构…...
Thread 类的基本用法
文章目录一、线程创建1.1 Thread的常见构造方法2.1 创建线程二、线程中断2.1 Thread的几个常见属性2.2 中断线程三、线程等待四、线程休眠五、获取线程实例一、线程创建 1.1 Thread的常见构造方法 方法说明Thread()创建线程对象Thread(Runnable target)使用Runnable对象创建线…...
2023.3.28 天梯赛训练赛补题(病毒溯源 , 龙龙送外卖 , 红色警报)
文章目录1.病毒溯源问题:求树的最长链长度和字典序最小的最长链思路:2.龙龙送外卖思路:3.红色警报:思路:1.病毒溯源 问题:求树的最长链长度和字典序最小的最长链 思路: 一开始用 bfs 做的 &a…...

917. 仅仅反转字母
917. 仅仅反转字母https://leetcode.cn/problems/reverse-only-letters/ 难度简单189 给你一个字符串 s ,根据下述规则反转字符串: 所有非英文字母保留在原有位置。所有英文字母(小写或大写)位置反转。 返回反转后的 s 。 示例…...

Linux-Git
一、总论 1.1 写在前面的话 这已经是我第三遍学Git相关操作了,可以说这个玩意是真的狗,因为确实用不到,不知道下个学期会不会用到,直到现在我刚刚学完,处于知识水平的巅峰,知道Git的具体功能ÿ…...

leetcode:2273. 移除字母异位词后的结果数组(python3解法)
难度:简单 给你一个下标从 0 开始的字符串 words ,其中 words[i] 由小写英文字符组成。 在一步操作中,需要选出任一下标 i ,从 words 中 删除 words[i] 。其中下标 i 需要同时满足下述两个条件: 0 < i < words.l…...

基于Python长时间序列遥感数据处理及在全球变化、物候提取、植被变绿与固碳分析、生物量估算与趋势分析等领域中的应用
植被是陆地生态系统中最重要的组分之一,也是对气候变化最敏感的组分,其在全球变化过程中起着重要作用,能够指示自然环境中的大气、水、土壤等成分的变化,其年际和季节性变化可以作为地球气候变化的重要指标。此外,由于…...
4.4---Spring框架之Spring事务(复习版本)
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。 Spring只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过 redo log 和 undo log实现的。 S…...

IP-Guard是否支持禁止客户端电脑卸载指定软件?
哪些浏览器支持设置窗口水印? 支持的浏览器有:搜狗浏览器、360安全浏览器、360极速浏览器、qq浏览器、谷歌浏览器、ie浏览器、edge浏览器 注意: 1.目标URL窗口水印不支持Firefox浏览器和猎豹浏览器 2.搜狗浏览器在兼容模式下,目标URL窗口水印不生效 3.部分浏览器(360安全…...

系统图标形状overlayapk
时间:2020/10/10 之前公司不允许csdn,笔记写在其它地方。最近整理过来 1、图标形状的overlay frameworks\base\packages\overlays目录 2、某一种形状的源码 默认配置在framework/base/core/res/res res下面放着图标形状的mask路径,这个值是一个矢量图…...

辅助编程coding的两种工具:Github Copilot、Cursor
目录Cursor简介下载地址:使用技巧:CHAT:example 1:注意:example 2:Github Copilot官网简介以插件方式安装pycharm自动写代码example 1:写一个mysql取数据的类example 2:写一个多重共线性检测的类…...

MySQL5.7安装教程
1.鼠标右击【MySQL5.7】压缩包(win11及以上系统需先点击“显示更多选项”)选择【解压到 MySQL5.7】 2.打开解压后的文件夹,双击运行【mysql-installer-community-5.7.27.0】 3.勾选【I accept the license terms】,点击【Next】 4…...

ML@sklearn@ML流程Part3@AutomaticParameterSearches
文章目录Automatic parameter searchesdemomodel_selection::Hyper-parameter optimizersGridSearchCVegRandomizedSearchCVegNoteRandomForestRegressorMSEpipeline交叉验证🎈egL1L2正则Next stepsUser Guide vs TutorialAutomatic parameter searches Automatic p…...
Ubuntu22安装OpenJDK
目录 一、是否自带JDK 二、 删除旧JDK(如果自带JDK满足需求就直接使用了) 三、下载OpenJDK 四、新建/home/user/java/文件夹 五、 设置环境变量 六、查看完成 附:完整版连接: 一、是否自带JDK java -version 二、 删除旧…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...