【jdk19虚拟线程 VS 普通线程】

news2024/11/27 12:36:36

文章目录

    • 一.什么是虚拟线程
    • 二.虚拟线程与普通线程的区别
      • 1.普通线程
      • 2.虚拟线程
      • 3. 实际应用中的区别
    • 三.上demo对比性能。
      • 1.线程池配置
      • 2.Service实现
      • 3.测试结果
    • 四.小结

一.什么是虚拟线程

虚拟线程,也称作轻量级线程,是由JVM直接管理的线程类型,它们区别于传统的操作系统线程(即平台线程)。虚拟线程的创建及切换所消耗的成本极低,这使得我们能够在应用程序中创建海量的线程,而不会带来显著的资源负担增加。这一特性在I/O密集型任务及高并发应用场景中尤其具有优势。

Java 19引入了虚拟线程(Virtual Threads),作为Project Loom项目的一部分,其目的在于简化并发编程的流程并增强高并发应用的性能表现。在Spring Boot应用中采用虚拟线程,可以大幅提升线程管理的效率。本文将指导你如何在Spring Boot中启用并有效利用虚拟线程。

二.虚拟线程与普通线程的区别

在Java编程语言中,线程构成了并发编程的基础单元。随着Java 19版本的发布,虚拟线程(Virtual Threads)被引入,相较于传统的普通线程(也被称为平台线程),虚拟线程展现出了明显的优势。先介绍完概念,等下直接上demo直观感受普通线程与虚拟线程之间的性能差距。
普通线程普通线程,也常被称作平台线程,是由操作系统直接进行管理的线程类型。

1.普通线程

  • 重量级:普通线程属于重量级资源,每一个线程都会直接映射到操作系统层面的一个原生线程上,这导致了线程的创建与销毁过程会伴随着相对较大的开销。
  • 内存占用:每个普通线程都会被分配一个独立的栈空间(其大小通常介于几百KB至几MB之间),这一特性限制了在同一时间内能够创建的线程总数。
  • 上下文切换开销大:鉴于普通线程是由操作系统直接管理的,因此在线程之间进行上下文切换时会带来相对较大的开销,这在一定程度上影响了高并发应用场景下的整体性能。
  • 适用场景:普通线程更适用于计算密集型任务即CPU 密集型任务,也就是那些需要长时间运行且任务数量相对较少的场景

2.虚拟线程

虚拟线程是由Java虚拟机(JVM)直接管理的轻量级线程,以下为其核心特性概述。

  • 轻量级:虚拟线程具备轻量级的特点,其创建与销毁的开销极低,几乎可以媲美于普通对象的创建过程。这一特性使得在应用程序中大量创建虚拟线程成为可能。
  • 内存占用低:虚拟线程的栈空间采用动态分配机制,初始时的内存占用极小,这为在有限的内存资源下创建更多的线程提供了可能。
  • 上下文切换开销小:由于虚拟线程是由JVM进行管理的,因此在进行上下文切换时所带来的开销相对较小。JVM能够针对线程的调度进行优化,从而进一步提升并发性能。
  • 对阻塞操作友好:当虚拟线程执行阻塞操作(例如I/O操作)时,它不会影响到底层的操作系统线程,这一特性显著提升了资源的利用效率。
  • 适用场景:虚拟线程非常适合用于高并发、I/O密集型任务场景,例如需要处理大量并发请求的服务器应用等。

3. 实际应用中的区别

在实际应用中,选择采用普通线程还是虚拟线程,这完全取决于具体的应用场景和实际需求。举例来说:

  • Web 服务器:在面对高并发的Web请求处理时,采用虚拟线程能够显著提升服务器的吞吐能力以及响应速度。这是因为虚拟线程能够轻松应对成千上万的并发请求,而不会因线程数量的激增而导致系统资源的枯竭。
  • 计算密集型任务:对于计算密集型任务而言,普通线程仍然是一个明智的选择。这类任务往往对CPU资源有着较高的需求,而不会频繁出现因大量I/O操作而导致的线程阻塞情况。
  • 混合场景:在一些复杂的混合应用场景中,我们可以灵活地结合使用普通线程和虚拟线程。例如,可以利用普通线程来处理那些需要长时间运行的计算密集型任务,同时借助虚拟线程来处理高并发的I/O密集型任务,以此来实现系统资源的最大化利用。

三.上demo对比性能。

我这里用的jdk22。

1.线程池配置

@Configuration
@EnableAsync
public class ThreadConfig {
    /**
     * 一个 Java普通线程对应一个操作系统线程,这些线程非常消耗资源。
     * 普通线程池定义:16个核心线程(模拟IO密集型任务,每个任务休眠1s),最大线程数50,阻塞队列1000:避免触发拒绝策略
     * @return
     */
    @Bean(name = "asyncTaskExecutor")
    public ThreadPoolTaskExecutor asyncTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(16);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(1000);
        executor.setThreadNamePrefix("Async-");
        executor.initialize();
        return executor;
    }

    /**
     * 虚拟线程是 Java 中最重要的创新之一。 它们是在 Project Loom 中开发的,自 Java 19 作为预览功能以来一直包含在 JDK 中,
     * 自 Java 21 作为最终版本 (JEP 444) 以来,它们已包含在 JDK 中。
     * @return
     */
    @Bean(name = "virtualThreadExecutor")
    public ExecutorService virtualThreadExecutor() {
        return Executors.newVirtualThreadPerTaskExecutor();
    }
}

2.Service实现

测试逻辑:
通过普通线程池提交1000个任务,每个任务休眠1s 对比 通过虚拟线程池提交1000个任务,每个任务休眠1s 。
每个任务执行完利用CountDownLatch计数器减1,主线程等待所有任务执行完(计数器归零),看普通线程池与虚拟线程分别执行完1000个任务的需要多久。

@Service
public class VirtualThreadServiceImpl implements VirtualThreadService {

    // 获取虚拟线程执行器
    @Autowired
    private ExecutorService virtualThreadExecutor;

    // 获取异步任务执行器
    @Autowired
    private ThreadPoolTaskExecutor asyncTaskExecutor;

    /**
     * 创建线程数量
     */
    private static Integer THREAD_NUM = 1000;

    /**
     * @throws InterruptedException
     */
    @Async("virtualThreadExecutor")
    public void testVirtualThreadTask() throws InterruptedException {
        Instant start = Instant.now();
        CountDownLatch taskLatch = new CountDownLatch(THREAD_NUM);
        for (int i = 0; i < THREAD_NUM; i++) {
            virtualThreadExecutor.execute(() -> {
                // 模拟耗时任务
                try {
                    Thread.sleep(1000);
                    System.out.println("虚拟线程任务完成!");
                    taskLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        taskLatch.await();
        Instant end = Instant.now();
        long duration = Duration.between(start, end).toMillis();
        System.out.println("虚拟线程方法执行时间: " + duration + " 毫秒");
    }

    @Async("asyncTaskExecutor")
    public void testNormalThreadTask() throws InterruptedException {
        Instant start = Instant.now();
        CountDownLatch taskLatch = new CountDownLatch(THREAD_NUM);
        for (int i = 0; i < THREAD_NUM; i++) {
            asyncTaskExecutor.execute(() -> {
                // 模拟耗时任务
                try {
                    Thread.sleep(1000);
                    System.out.println("普通线程任务完成!");
                    taskLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        taskLatch.await();
        Instant end = Instant.now();
        long duration = Duration.between(start, end).toMillis();
        System.out.println("普通线程方法执行时间: " + duration + " 毫秒");
    }
}

3.测试结果

  • 普通线程执行完1000个任务耗时:67563 毫秒 约等于68s钟。
    在这里插入图片描述

  • 虚拟线程执行完1000个任务耗时:1071 毫秒,约1s。 快了足足68倍!!!
    在这里插入图片描述
    可能小伙伴们会有疑问:

  • 这样对比维度不太准确,因为上面普通线程池定义:16个核心线程(模拟IO密集型任务,每个任务休眠1s),最大线程数50,阻塞队列1000。这样会造成提交1000个任务的时候基本都进入阻塞队列了,真正干活的只有16个核心线程!!!

  • 但是我们从另一个角度来看,我们虚拟线程是由jvm管控的轻量级线程可以完全高效处理过来这1000个任务,而且没有核心线程数、最大线程数、任务队列这一说,是不是也可以说明虚拟线程在处理IO密集型任务的优势。

  • 如果我把普通线程池定义:核心线程换成1000(每个任务都有线程执行,不用等待),即每个任务对应一个操作系统线程,让1000个核心线程干活,处理1000个任务(生产不可能这样定义,失去了线程池的意义),执行时间也花了近虚拟线程1倍的时间,也干不过虚拟线程!!!
    从以上方面对比是不是也体现了虚拟线程的优势所在:轻量级、高效处理高并发的 I/O 密集型任务、上下文切换小。
    在这里插入图片描述

四.小结

主要介绍下jdk19的新特性虚拟线程,真是性能优化的又一大利器啊!如果小伙伴们项目里面jdk有紧跟潮流,在合适的业务场景不妨试试吧~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jmeter入门:脚本录制

1.设置代理。 网络连接-》代理-》手动设置代理. ip&#xff1a; 127.0.0.1&#xff0c; port&#xff1a;8888 2. add thread group 3. add HTTP(s) test script recorder, target controller chooses Test plan-> thread Group 4. click start. then open the browser …

Golang | Leetcode Golang题解之第467题环绕字符串中唯一的子字符串

题目&#xff1a; 题解&#xff1a; func findSubstringInWraproundString(p string) (ans int) {dp : [26]int{}k : 0for i, ch : range p {if i > 0 && (byte(ch)-p[i-1]26)%26 1 { // 字符之差为 1 或 -25k} else {k 1}dp[ch-a] max(dp[ch-a], k)}for _, v :…

Java主流框架项目实战——SpringBoot入门

单元1-1 1&#xff09; IDEA工具安装好 2&#xff09; Maven安装&#xff0c;配置好 IDEA安装及永久试用 配置maven 单元1-2 使用aliyun(https://start.aliyun.com/)创建一个spring boot项目&#xff0c;hello world&#xff01; 构建项目 1&#xff09;构建项目 直接默认…

MicroFlow:一种高效的基于Rust的TinyML推理引擎

英文论文标题&#xff1a;MICROFLOW: AN EFFICIENT RUST-BASED INFERENCE ENGINE FOR TINYML 中文论文标题&#xff1a;MicroFlow&#xff1a;一种高效的基于Rust的TinyML推理引擎 作者信息&#xff1a; Matteo Carnelos&#xff0c;意大利帕多瓦大学&#xff0c;Grepit AB,…

什么软件可以晚上睡觉录音

什么软件可以晚上睡觉录音&#xff0c;在日常生活中&#xff0c;我们常常忽略夜间的声音&#xff0c;然而这些声音有时可能会揭示重要信息&#xff0c;比如打鼾情况、说梦话、甚至是潜在的睡眠问题。因此&#xff0c;一款适合夜间录音的软件对于关注健康及生活细节的人来说至关…

在IDEA中配置Selenium和WebDriver

前言&#xff1a; 在当今自动化测试和网络爬虫的领域&#xff0c;Selenium是一个被广泛使用的工具。它不仅能够模拟用户与浏览器的交互&#xff0c;还能进行网页测试和数据抓取。而为了使用Selenium与谷歌/Edge浏览器进行自动化测试&#xff0c;配置合适的WebDriver至关重要。本…

【时时三省】(C语言基础)指针笔试题8

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 笔试题8 c是个数组 它的每个元素是char* 它初始化了四个字符串 把这四个字符串的首字符的地址 传到了c里面 cp有四个元素 每个元素的类型是char** 所以c3指向FORST c2指向POINT c1指向NE…

数学建模算法与应用 第9章 支持向量机及其方法

目录 9.1 支持向量机的基本原理 核函数的种类&#xff1a; 9.2 支持向量机的Matlab命令及应用 Matlab代码示例&#xff1a;二分类支持向量机 9.3 乳腺癌的诊断案例 Matlab代码示例&#xff1a;乳腺癌数据分类 9.4 支持向量回归&#xff08;SVR&#xff09; Matlab代码示…

uibot发送邮件:自动化邮件发送教程详解!

uibot发送邮件的操作指南&#xff1f;uibot发送邮件的两种方式&#xff1f; 在现代办公环境中&#xff0c;自动化流程的引入极大地提高了工作效率。uibot发送邮件功能成为了许多企业和个人实现邮件自动化发送的首选工具。AokSend将详细介绍如何使用uibot发送邮件。 uibot发送…

【AIGC】寻找ChatGPT最佳推理步骤:CoT思维链技术的探索与应用

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;CoT思维链概述&#x1f4af;CoT思维链在大型语言模型中的应用&#x1f4af;CoT思维链改变对模型推理能力的理解和改进方式多样化应用场景挑战与未来发展总结 &#x1f4a…

鸿蒙NEXT开发-动画(基于最新api12稳定版)

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

用FPGA做一个全画幅无反相机

做一个 FPGA 驱动的全画幅无反光镜数码相机是不是觉得很酷&#xff1f; 就是上图这样。 Sitina 一款开源 35 毫米全画幅 (3624 毫米) CCD 无反光镜可换镜头相机 (MILC)&#xff0c;这个项目最初的目标是打造一款数码相机&#xff0c;将 SLR [单镜头反光] 相机转换为 DSLR [数码…

探索Semantic Kernel:开启AI编程新篇章(入门篇)

文章目录 一、引言二、什么是Semantic Kernel&#xff1f;三、为什么选择Semantic Kernel&#xff1f;四、Semantic Kernel的核心特性4.1企业级4.2 自动化业务流程4.3 模块化和可扩展性 五、Semantic Kernel入门5.1 安装SDK5.2 编写控制台应用1. 配置2.实例3.示例一&#xff1a…

【漏洞复现】某知识付费纯净发卡小程序系统存在SQL注入漏洞

漏洞描述 知识吾爱纯净版小程序源码,附详细视频+文字教程【小白可0基础搭建】跟随教程步骤即可简单搭建属于自己的知识付费小程序,实现支付变现+流量主收益,快速建立自己的IP知识付费小程序源码包括以下功能:会员管理:支持用户注册、登录、个人信息管理等功能,以及会员等…

《系统架构设计师教程(第2版)》第18章-安全架构设计理论与实践-01-安全架构概述

文章目录 1. 信息安全面临的威胁2. 安全架构的定义和范围2.1 安全架构的概念2.2 安全架构的范围2.3 安全架构应具备的特性2.4 安全技术2.5 过程 3. 与信息安全相关的国内外标3.1 国外标准3.2 国内标准3.2.1 标准缩写含义3.2.2 主要技术标准1&#xff09;国家标准2&#xff09;特…

安全网络架构

网络安全解决方案是指通过一系列技术和措施来保护网络系统和数据的安全。它涉及多个方面&#xff0c;包括网络设备的防护、数据的加密和备份、安全策略的制定和执行等。以下是一些常见的网络安全解决方案&#xff1a; 防火墙&#xff1a;防火墙是一种硬件或软件设备&#xff0c…

怎么将视频原声提出来?视频原声提取,让创作更自由

在数字媒体时代&#xff0c;视频已成为我们日常生活和工作中不可或缺的一部分。有时&#xff0c;我们可能想要提取视频中的音频部分&#xff0c;无论是为了制作音频素材、学习语言&#xff0c;还是为了其他创意用途。那么&#xff0c;怎么将视频原声提出来呢&#xff1f;本文将…

ChatTTS 本地安装和测试

Ubuntu 22服务器&#xff0c;3.9/3.10都可以&#xff0c;但是 3.11不可以 sudo apt install python3.10 apt install python3.10 python3.10-dev #ubuntu 22 安装python3.10对应的pip3.10 # 下载 get-pip.py curl -sS https://bootstrap.pypa.io/get-pip.py -o get-pip.py # 使…

小北的技术博客:探索华为昇腾CANN训练营与AI技术创新——Ascend C算子开发能力认证考试(初级)

前言 哈喽哈喽友友们,这里是zyll~(小北)智慧龙阁的创始人及核心技术开发者。在技术的广阔天地里,我专注于大数据与全栈开发,并致力于成为这一领域的新锐力量。通过智慧龙阁这个平台,我期望能与大家分享我的技术心得,共同探索技术的无限可能。 Ascend C编程:小北的技术…

<Project-8 pdf2tx-MM> Python Flask应用:在浏览器中翻译PDF文件 NLTK OCR 多线程 指定翻译器 改进后的P6

项目概述 名字解释 缩写&#xff1a; pdf2tx-MM pdf file transfer to text content with Multi-threads and Multi-translators pdf2tx-MM 是一个基于 Flask 的 Web 应用程序&#xff0c;提供将 PDF 文件中的内容提取、翻译并展示。使用者上传 PDF 文件&#xff0c;应用程序…