什么是JDK21虚拟线程

JDK21虚拟线程

  • 1. 来一段小故事
  • 2. 什么是虚拟线程
  • 3. 虚拟线程的几个关键特点
  • 4.细说关键特点
    • 1.为什么轻量级的
      • 1.传统线程运行时间
      • 2.虚拟线程运行时间
      • 3.对垃圾回收的影响
    • 2.非绑定OS线程的魅力所在
    • 3.和传统相比为何易于使用
    • 4.阻塞优化有什么好处
      • 1.什么是阻塞优化
      • 2.JDK 21虚拟线程的阻塞优化
      • 3.传统线程的阻塞

1. 来一段小故事

  1. 假设博主经营一家快递公司,以前呢,每送一件包裹,你都得安排一辆大卡车出去,哪怕包裹很小。这样操作虽然可靠,但是成本高,效率低,特别是当有很多小包裹要送的时候,大卡车们忙着到处跑,油费不少花,还经常堵在路上。
  2. JDK21的虚拟线程就像是引入了一种新型的送快递方式。现在,你可以用很多轻便的电动车来送包裹,这些电动车就是“虚拟线程”。它们成本低,启动快,数量可以很多,应对大量小任务轻轻松松。当电动车(虚拟线程)在等红灯或者充电(执行耗时操作如读写文件)时,司机(JVM)就会让其他电动车接手其他包裹,保证路上总有车在跑,效率大大提升。
  3. 而且,用这些电动车安排送货任务非常简单,就像以前安排卡车一样,只是现在你有了更灵活、更高效的工具。当然,对于那些确实需要大卡车的大件货物(重量级计算任务),你还是可以用传统的卡车(操作系统线程),两种方式结合使用,让快递业务更加高效顺畅。这就是JDK21虚拟线程的通俗解释。

2. 什么是虚拟线程

  1. 首先,让我们揭开虚拟线程的神秘面纱。虚拟线程,或称为协程,是一种由JVM直接管理的轻量级线程。不同于操作系统级别的传统线程,每个虚拟线程占用的资源极小,使得在同一进程中可以轻松创建成千上万条这样的线程,极大地提升了系统对于高并发场景的应对能力。

  2. Thread.ofVirtual():这是手动启动虚拟线程的简便方式,只需一行代码,你就能为特定任务分配一个虚拟线程。

  3. 结构化并发:JDK 21引入的预览特性之一,让并发控制更加有序和安全。通过结构化并发,程序可以在明确的生命周期边界内自动创建和管理虚拟线程,减少了死锁和竞态条件的风险。

  4. Executors的革新:类似线程池的使用模式,但针对虚拟线程进行了优化,让你能够以熟悉的API享受虚拟线程带来的性能提升。

  5. 用一串代码来体验一下:

public class VirtualThreadDemo {
    public static void main(String[] args) {
        // 创建一个虚拟线程工厂
        var threadFactory = Thread.ofVirtual().factory();
        
        // 使用虚拟线程执行任务
        for (int i = 0; i < 10_000; i++) {
            var vt = threadFactory.newThread(() -> {
                System.out.println('Hello from Virtual Thread: ' + Thread.currentThread());
            });
            vt.start();
        }
        
        // 等待所有虚拟线程完成(实际应用中需考虑更优雅的同步机制)
        // 这里仅作演示,未加入等待逻辑
    }
}
  1. 在上面代码中,我们使用Thread.ofVirtual().factory()创建了一个虚拟线程工厂,随后启动了1万个虚拟线程,每个线程打印出自己的信息。这在传统线程模型下几乎是不可想象的任务量,但在虚拟线程的支持下,却变得轻而易举

3. 虚拟线程的几个关键特点

  • 轻量级:虚拟线程的创建和销毁成本远低于操作系统线程,使得应用程序能够创建成千上万甚至百万级别的线程,这对于高并发场景特别有利。

  • 非绑定OS线程:虚拟线程不由操作系统直接管理,而是由Java虚拟机(JVM)管理。这意味着虚拟线程可以在较少的操作系统线程上实现复用,减少上下文切换开销和资源消耗。

  • 易于使用:开发者可以像创建常规线程一样创建虚拟线程,但不需要担心线程池大小调整或过多线程带来的性能问题。

  • 阻塞优化:当虚拟线程执行阻塞操作(如I/O操作、锁等待等)时,它们会被暂停,而其底层的载体线程(carrier thread,对应的操作系统线程)则可以被释放去执行其他虚拟线程,从而提高了整体的并发效率。

  • 调度由JVM控制:虚拟线程的生命周期、状态管理、任务提交、休眠和唤醒等操作完全由JVM控制,提供了更好的可控制性和灵活性。

4.细说关键特点

1.为什么轻量级的

1.传统线程运行时间

1.传统线程创建示例:

public class PlatformThreadExample {
    public static void main(String[] args) {
        long startTime = System.nanoTime();

        for (int i = 0; i < 10000; i++) {
            new Thread(() -> doWork()).start();
        }

        System.out.printf("创建==> %d 个线程,用时==> %d 纳秒",
                10000, System.nanoTime() - startTime);
    }

    private static void doWork() {
        // 简单的工作逻辑
}

2.运行结果
在这里插入图片描述
3.运行时间为:1041478300纳秒

2.虚拟线程运行时间

1.虚拟线程创建示例

import java.util.concurrent.ThreadFactory;

public class VirtualThreadExample {
    public static void main(String[] args) {
        long startTime = System.nanoTime();
        ThreadFactory virtualThreadFactory = Thread.ofVirtual().factory();
        
        for (int i = 0; i < 1_000_000; i++) {
            Thread vt = virtualThreadFactory.newThread(() -> doWork());
            vt.start();
        }
        
        System.out.printf("创建==> %d 个线程,用时==> %d 秒",
                1_000_000, System.nanoTime() - startTime);
    }

    private static void doWork() {
        // 简单的工作逻辑
    }
}

2.运行结果
在这里插入图片描述
3.运行时间为:536852800纳秒

3.对垃圾回收的影响

  1. 资源消耗减少:虚拟线程相较于操作系统线程消耗更少的内存资源。因为它们不需要分配大量的栈空间(通常虚拟线程的栈空间可以动态调整且较小),减少了堆外内存的占用,这可能导致GC活动减少,尤其是在大量线程并发的场景下。

  2. 栈内存管理:虚拟线程的栈是动态分配和释放的,这意味着当虚拟线程不再使用或阻塞时,其占用的栈内存可以更快地被回收或复用,减少了长时间运行过程中累积的内存碎片,有助于GC更高效地进行内存整理。

  3. 生命周期管理:虚拟线程的生命周期通常较短,尤其是在处理短暂任务后迅速结束,这减少了需要跟踪和回收的对象数量,减轻了GC的压力。

  4. GC频率:在高并发场景下,由于每个虚拟线程的内存占用减少,整体的内存分配速率可能降低,导致GC事件的发生频率相对降低。

  5. GC停顿时间:由于虚拟线程的轻量级特性,它们对堆内存的影响减小,可能减少因大对象分配或老年代回收而导致的长停顿时间。

  6. 内存使用效率:虚拟线程栈的高效管理有助于维持稳定的内存使用水平,减少内存碎片,使得内存使用更加平滑,GC曲线可能展现出更加平稳的趋势。

2.非绑定OS线程的魅力所在

  1. 资源效率:虚拟线程消耗的内存远低于传统OS线程,因为它们共享JVM的资源,减少了对系统资源的争抢。

  2. 上下文切换成本低:JVM优化了虚拟线程之间的切换过程,几乎感受不到额外开销,提升了整体性能。

  3. 简化编程模型:开发者不再需要复杂的线程池配置,可以像处理普通对象一样创建和销毁虚拟线程,降低了并发编程的门槛。

  4. 用一个生活中的案例比喻:设想一家在线零售平台在大促期间面临亿级用户请求的挑战。使用虚拟线程前,服务器可能因线程管理和资源分配问题而崩溃。但在采用JDK 21后,每个用户请求都能被迅速封装进一个轻量级的虚拟线程中,JVM智能调度确保所有请求得到高效、有序的处理,不仅提升了用户体验,还显著降低了运维成本。

  5. 总而言之,JDK 21中的虚拟线程及其非绑定OS线程特性,它以极简的资源占用、高效的执行效率以及友好的编程模型,为开发者铺设了一条通往高性能并发应用的康庄大道。

3.和传统相比为何易于使用

1.先来用代码写一个示例:

public class HelloWorld {
    public static void main(String[] args) {
        Thread vThread = Thread.startVirtualThread(() -> {
            System.out.println('Hello, Virtual World!');
        });
        vThread.join(); // 等待虚拟线程结束
    }
}

2.就像代码中所写,创建一个虚拟线程就像调用:Thread.startVirtualThread(Runnable task)

3.这么简单,无需复杂的线程池配置,也不必担心过多线程导致的性能瓶颈

4.资源效率提升:传统线程每个都映射到操作系统层面,消耗显著资源。而虚拟线程则不然,它们数量众多却几乎不增加额外开销,使得应用程序能够更加灵活地应对高并发场景

4.阻塞优化有什么好处

1.什么是阻塞优化

1.用一个生活案例进行举例:假设博主正站在繁忙的十字路口,车辆川流不息,但偶尔因红灯而停滞不前,造成交通短暂拥堵。这就像我们的程序在执行过程中,线程遇到IO操作或锁竞争时被迫等待的情景。现在,想象有一种魔法,能让停滞的车辆瞬间消失,道路重新畅通无阻,直到绿灯亮起它们才再次出现——这就是JDK 21虚拟线程阻塞优化带给我们的奇迹。

2.阻塞优化的魅力:当虚拟线程遇到IO阻塞或类似情况时,JVM会施展它的“隐形斗篷”,将这个虚拟线程从其载体的平台线程上移除,释放该平台线程去处理其他任务。这一过程无需程序员显式编码,完全由JVM自动完成。相比之下,传统线程在阻塞时会占用一个操作系统线程,即使不做任何工作也是如此,白白浪费了宝贵的系统资源。

3.简要浏览一段代码:

public class VirtualThreadDemo {
    public static void main(String[] args) {
        // 创建一个虚拟线程执行网络请求
        Thread vThread = Thread.startVirtualThread(() -> {
            var response = fetchFromNetwork('https://editor.csdn.net/md?not_checkout=1&spm=1001.2014.3001.5352&articleId=139201961');
            System.out.println('Data fetched: ' + response);
        });
        
        // 主线程继续执行其他任务
        System.out.println('Main thread doing other work...');
    }
    
    static String fetchFromNetwork(String url) {
        // 假设这是一个耗时的网络请求
        // 在此期间,虚拟线程会被透明卸载,不会阻塞主线程或其他任务
        return 'dummy data';
    }
}

4.在这段代码中,当我们发起网络请求时,虚拟线程会自动处理潜在的阻塞,确保主线程和其他任务不受影响,展现了其高效的并发能力。

2.JDK 21虚拟线程的阻塞优化

  • 自动的非阻塞转换:虚拟线程在执行到阻塞操作时,JVM会自动将其从当前的载体线程(即实际的平台线程)上移除,释放载体线程去执行其他任务,而不会直接阻塞操作系统线程。这意味着即使虚拟线程阻塞,也不再消耗宝贵的系统资源。

  • 轻量级上下文切换:虚拟线程之间的上下文切换比传统线程更为轻量,因为它们不涉及操作系统级别的状态保存和恢复,减少了开销。

  • 透明性:对于开发者而言,虚拟线程上的阻塞操作看起来像是同步的,但底层实际上是以非阻塞方式高效处理,无需手动编写复杂的异步回调逻辑,代码更加简洁、直观。

  • 资源效率:由于虚拟线程不直接占用操作系统资源,可以创建数以百万计的线程而不会耗尽系统资源,使得高度并发的应用成为可能。

代码示例:


// 假设代码在JDK 21环境下,使用虚拟线程执行阻塞操作
import java.util.concurrent.*;

public class VirtualThreadBlockingOptimized {
    public static void main(String[] args) {
        var executor = Executors.newVirtualThreadPerTaskExecutor();
        
        Future<?> future = executor.submit(() -> {
            try {
            	 // 同样是阻塞操作,但虚拟线程优化了阻塞处理
                Thread.sleep(1000);
                System.out.println("虚拟线程完成阻塞操作");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        System.out.println("主线程继续执行,虚拟线程阻塞不会阻塞载体线程");
        
        try {
        	// 等待虚拟线程完成,非必须,仅为演示
            future.get(); 
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        
        executor.shutdown();
    }
}

3.传统线程的阻塞

在传统的线程模型中,每个线程直接映射到操作系统的一个线程。当线程执行到阻塞操作,如I/O操作或等待锁时,操作系统会将该线程挂起,直到阻塞条件解除。传统线程的阻塞优化通常涉及:

  • 非阻塞I/O(NIO):使用如Java NIO来避免在I/O操作时阻塞线程,转而使用回调或者轮询机制来通知数据准备好。
  • 锁优化:如自旋锁、锁粗化、锁消除等技术减少线程因竞争锁而阻塞的情况。
  • 线程池:通过复用线程来减少频繁创建和销毁线程的开销,同时限制并发线程的数量以防止资源耗尽。

代码示例:

public class TraditionalThreadBlocking {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
            	// 阻塞操作,如读取文件或网络I/O
                Thread.sleep(1000); 
                System.out.println("传统线程完成阻塞操作");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        thread.start();
        System.out.println("主线程继续执行,但系统资源被阻塞的线程占用");
    }
}

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

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

相关文章

配置docker阿里云镜像地址

一、安装docker的步骤&#xff1a; 1.yum install -y yum-utils 2.yum-config-manager --add-repo http://mirrors.aliyun.com/docker- ce/linux/centos/docker-ce.repo --配置阿里云仓库3.yum makecache fast4.yum install docker-ce -y5.docker version …

【LVGL_Linux安装NXP的Gui-Guider】

GUI Guider是恩智浦为LVGL开发了一个上位机GUI设计工具&#xff0c;可以通过拖放控件的方式设计LVGL GUI页面&#xff0c;加速GUI的设计。 虽然他只支持自家芯片&#xff0c;但是应用层我们可以直接拿来用作其他MCU上。 GUI-Guider 下载 NXP官网下载&#xff1a;链接&#xff1…

关于sklearn决策树手动指定节点进行剪枝调整的实现

一、决策树剪枝 决策树的剪枝方式有两种&#xff0c;预剪枝和后剪枝&#xff0c;后剪枝在python的sklearn方法中提供了CCP代价复杂度剪枝法&#xff08;Cost Complexity Pruning&#xff09;具体实现代码如下&#xff1a; # -*- coding: utf-8 -*- from sklearn.datasets imp…

AI模型抉择:开源VS闭源,谁主沉浮?

AI模型抉择&#xff1a;开源VS闭源&#xff0c;谁主沉浮&#xff1f; &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &am…

软件设计师备考 | 案例专题之数据库设计 概念与例题

相关概念 关注上图中的两个部分&#xff1a; 概念结构设计 设计E-R图&#xff0c;也即实体-联系图。 工作步骤&#xff1a;选择局部应用、逐一设计分E-R图、E-R图合并。进行合并时&#xff0c;它们之间存在的冲突主要有以下3类&#xff1a; 属性冲突。同一属性可能会存在于…

如何通过OpenHarmony的音频模块实现录音变速功能?

简介 OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;是由开放原子开源基金会孵化及运营的开源项目&#xff0c;是面向全场景、全连接、全智能时代的智能物联网操作系统。 多媒体子系统是OpenHarmony系统中的核心子系统&#xff0c;为系统提供了相机、…

MySQL中视图是什么,有什么作用

目录 一、视图的简介 1.1 什么是视图&#xff1f; 1.2 为什么使用视图&#xff1f; 1.3 视图有哪些规则与限制&#xff1f; 1.4 视图能否更新&#xff1f; 二、视图的创建 三、视图的作用 3.1 用视图简化复杂的联结 3.2 用视图格式化检索出的数据 3.3 用视图过滤数据…

redisson 使用fastJson2序列化

前因&#xff1a;一个项目&#xff1a;有人用redisTemplete存数据&#xff08;使用了fastjson2&#xff09;&#xff0c;使用redisson取的时候就会报错。要让redisTemplete与redisson序列化一致 一、自定义序列化器 import com.alibaba.fastjson2.JSON; import com.alibaba.fa…

LeetCode //C - 119. Pascal‘s Triangle II

119. Pascal’s Triangle II Given an integer rowIndex, return the rowIndexth (0-indexed) row of the Pascal’s triangle. In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown: Example 1: Input: rowIndex 3 Output: …

集中抄表电表是什么?

1.集中抄表电表&#xff1a;简述 集中抄表电表&#xff0c;又称为远程抄表系统&#xff0c;是一种现代化电力计量技术&#xff0c;为提升电力行业的经营效率和客户服务质量。它通过自动化的形式&#xff0c;取代了传统人工抄水表&#xff0c;完成了数据信息实时、精确、高效率…

C# 深拷贝和浅拷贝

文章目录 1.深拷贝2.浅拷贝3.拷贝类4.浅拷贝的实现5.深拷贝实现5.1 浅拷贝对象&#xff0c;对引用类型重新一个个赋值5.2 反射实现5.3 利用XML序列化和反序列化实现 1.深拷贝 拷贝一个对象时&#xff0c;不仅仅把对象的引用进行复制&#xff0c;还把该对象引用的值也一起拷贝。…

Python基于PyQt6制作GUI界面——按钮

示例对应的制作的 ui文件 界面如下所示。 <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0"><class>Form</class><widget class"QWidget" name"Form"><property name"geom…

C#使用开源操作库MiniExcel操作Excel

简介 MiniExcel 简单、高效避免 OOM 的.NET 处理 Excel 查、写、填充数据工具。 目前主流框架大多需要将数据全载入到内存方便操作&#xff0c;但这会导致内存消耗问题&#xff0c;MiniExcel 尝试以 Stream 角度写底层算法逻辑&#xff0c;能让原本 1000 多 MB 占用降低到几 …

2024年【N1叉车司机】考试题及N1叉车司机找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 N1叉车司机考试题参考答案及N1叉车司机考试试题解析是安全生产模拟考试一点通题库老师及N1叉车司机操作证已考过的学员汇总&#xff0c;相对有效帮助N1叉车司机找解析学员顺利通过考试。 1、【多选题】《特种设备使用…

微服务-系统架构

微服务&#xff1a; 系统架构的演变 单一应用架构 早期的互联网应用架构&#xff0c;大量应用服务 功能 集中在一个包里&#xff0c;把大量的应用打包为一个jar包&#xff0c;部署在一台服务器&#xff0c;例如tomcat上部署Javaweb项目 缺点:耦合度高&#xff0c;一台服务器…

springboot项目中图片上传之后需要重启工程才能看到图片?

需求背景 最近在做一个用户自定义上传头像的小需求&#xff0c;用户上传头像然后需要立马回显。 需求是很常见的、正当的需求。如果不使用到对象存储这类服务&#xff0c;我们把用户头像的图片文件仅存在本地就可以了。我们在开发的过程中为了工程管理方便通常下意识会将图片…

PyTorch安装与配置

前言 参考文档&#xff1a;https://github.com/TingsongYu/PyTorch-Tutorial-2nd 环境配置之Anaconda 解释器——python.exe&#xff0c;是人类与CPU之间的桥梁&#xff0c;需要配置系统环境变量 Anaconda&#xff1a;集成环境&#xff0c;包管理器 Conda 安装 Anaconda&am…

【vs2022】安装copilot和reshaper

直接安装新版vs 17.10 自带集成的copilot支持安装resharper 可以跳过市场里的reshper安装好后依然可以直接使用vs。 resharper 2024.1.2 市场里还是i老版本&#xff1a; copilot 不兼容,这个是之前市场安装的版本 官方建议用vs intall 安装 安裝 GitHub Copilot GitHub.Co…

【CAN】STM32新能源汽车CAN通信实现过程

【CAN】STM32新能源汽车CAN通信实现过程 文章目录 前言一、软件1.PA11、PA12口配置2.PB8、PB9口配置 二、接线图三、硬件原理图四、上位机总结 前言 【电机控制】直流有刷电机、无刷电机汇总——持续更新 使用工具&#xff1a; 1.控制器——STM32F103C8T6 2.仿真器——STLINK …

Python 拼图游戏

拼图游戏(puzzle)是一种常见的益智游戏&#xff0c;玩家通过拖动图块来正确拼接成完整的图片。 由一张原图&#xff0c;分割成图块&#xff0c;拼图块的大小将会根据行列数自动调整&#xff0c;然后随机打乱&#xff0c;玩家通过拖拽图块&#xff0c;最后复原原图。 &#x1f…