什么是JDK21虚拟线程

news2024/11/25 3:52:33

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("主线程继续执行,但系统资源被阻塞的线程占用");
    }
}

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

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

相关文章

基于SSH的母婴用品销售管理系统带万字文档

文章目录 母婴商城系统一、项目演示二、项目介绍三、系统部分功能截图四、万字论文参考五、部分代码展示六、底部获取项目源码和万字论文参考&#xff08;9.9&#xffe5;带走&#xff09; 母婴商城系统 一、项目演示 母婴商城系统 二、项目介绍 基于SSH的母婴商城系统 系统…

海外仓储管理系统:提升效率,标准化海外仓管理,科技赋能业务

海外仓作为跨境物流的关键一环&#xff0c;完全可以说海外仓的效率直接决定了后续物流的整体运作效率。 对于海外仓而言&#xff0c;一套高效&#xff0c;易用的海外仓储系统&#xff0c;无疑将成为提升企业竞争力的重要工具&#xff0c;帮助海外仓实现从野蛮生长到标准化管理…

边用边充电影响寿命吗?看看计算机指令组成与操作类型

计算机指令集体系结构之指令 指令由操作码和地址码字段组成。 操作码指明了指令要完成的操作。 长度可以固定&#xff1a;比如RISC&#xff08;reduced instruction set computer&#xff09;精简指令集计算机 与之对应的RISC&#xff08;复杂指令集计算机&#xff09;&…

【C++进阶】AVL树

0.前言 前面我们已经学习过二叉搜索树了&#xff0c;但如果我们是用二叉搜索树来封装map和set等关联式容器是有缺陷的&#xff0c;很可能会退化为单分支的情况&#xff0c;那样效率就极低了&#xff0c;那么有没有方法来弥补二叉搜索树的缺陷呢&#xff1f; 那么AVL树就出现了&…

【C++】类与对象——多态详解

目录 一、多态的定义 二、重载、覆盖(重写)、隐藏(重定义)的对比 三、析构函数重写 四、C11 override 和 final 1. final 2. override 五、抽象类 六、多态的原理 一、多态的定义 多态是在不同继承关系的类对象&#xff0c;去调用同一函数&#xff0c;产生了不同的行为…

【机器学习】机器学习与大型预训练模型的前沿探索:跨模态理解与生成的新纪元

&#x1f512;文章目录&#xff1a; &#x1f4a5;1.引言 ☔2.跨模态理解与生成技术概述 &#x1f6b2;3.大型预训练模型在跨模态理解与生成中的应用 &#x1f6f4;4.前沿探索与挑战并存 &#x1f44a;5.未来趋势与展望 &#x1f4a5;1.引言 近年来&#xff0c;机器学习领…

使用C/C++ API接口操作 Zookeeper 数据

ZooKeeper 支持 Java 和 C 的API接口。本文将介绍使用 C/C 语言客户端库的编译安装和使用入门。 一、编译安装 PS&#xff1a;就在上一篇文章还觉得安装和配置 jdk 、maven 麻烦&#xff0c;所以当时选择 apache-zookeeper-[version]-bin.tar.gz 的版本。然而&#xff0c;本文…

【C++要哮着学】类和对象

文章目录 前言面向过程和面相对象初步认识类的定义类的访问限定符及封装访问限定符封装 类的作用域类的实例化类对象模型如何计算类的大小结构体内存对齐规则类对象的存储方式1.对象中包含类的各个成员2.代码只保存一份&#xff0c;在对象中保存存放代码的地址3.只保存成员变量…

权限维持--linux

隐藏文件/夹&-开头文件 如何创建: 在文件名之前加.即可 touch .1.s 如何清除、查找&#xff1a; ls -al rm -fr -文件 已-开头的文件直接读取是不行的需要带目录 隐藏时间戳 ①用其他文件的时间 touch -r zww.php testq.txt 如何清除、查看&#xff1a; stat test…

KDE-Ambari-Metrics-Collector问题排查解决手册

文档说明 本文档是为了解决KDE平台的Ambari-Metrics-Collector服务在运行时遇到的问题而提供的问题排查和解决方法的参考文档 说明: 当前的Ambari-Metrics-Collector服务包括了ams-collector和ams-hbase两个程序,在Ambari-Metrics-Collector安装的节点执行ps -elf|grep am…

【算法】前缀和——二维前缀和模板题

本节博客是通过——二位前缀和模板题来介绍前缀和二维算法&#xff0c;有需要借鉴即可。 目录 1.题目2.暴力求解3.二维前缀和算法3.代码示例4.总结 1.题目 题目链接&#xff1a;LINK 2.暴力求解 这里我们首先想到的就是一个暴力求解的方式&#xff0c;挨个需要的进行遍历就…

基于SA模拟退火优化算法的TSP问题求解matlab仿真,并对比ACO蚁群优化算法

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于SA模拟退火优化算法的TSP问题求解matlab仿真,并对比ACO蚁群优化算法,对比两个算法的仿真时间&#xff0c;收敛曲线&#xff0c;以及路径规划的结果&#xff0…

独享IP是原生IP吗?

原生IP&#xff1a; 原生IP是指由Internet服务提供商&#xff08;ISP&#xff09;直接分配给用户的IP地址&#xff0c;这些IP地址通常反映了用户的实际地理位置和网络连接。原生IP是用户在其所在地区或国家使用的真实IP地址&#xff0c;与用户的物理位置直接相关。在跨境电商中…

从零训练yolov8

1.收集数据 2.数据标注 pip install labelimg3.划分数据集 0.2的验证机0.8的训练集 import os from shutil import copyfile from sys import exit import randomsource r"D:\Data\imgs\screenc" \\ target_train r"D:\Data\imgs\datasets\mydata\images\t…

访存优化实践之一 : CPU、GPU、DDR与访存路径介绍

一、CPU的访存路径 上图是目前主流的CPU架构介绍。可以看到,CPU的访存路径:先经过MMU,然后经过Cache,最后到达DRAM。这其中涉及到的关键内容为基于MMU的内存管理以及缓存机制。 1.1、基于MMU的内存管理 众所周知,在计算机设计之处是没有虚拟地址的概念的,CPU发出的地址即…

win中的vscode利用ssh插件,在同一台电脑的virtualbox虚拟出来的ubuntu中编译,调试设置方法

vscode中安装ssh插件virtualbox7.0中的设置&#xff1a; 在网络管理器中添加host-only网卡&#xff0c;用来主机和虚拟机双向通信。这个网卡能在win的设备管理器里面看到手动配置网卡&#xff0c;其中ip地址是另一个网段的&#xff0c;主机ip地址是192.168.1.1。这个网卡对于虚…

ELK 日志监控平台(二)- 优化日志格式

文章目录 ELK 日志监控平台&#xff08;二&#xff09;- 优化日志格式1.日志输出要点2.优化应用的日志格式2.1.确定日志输出要点来源2.1.1.服务名称2.1.2.服务环境2.1.3.日志级别2.1.4.日志输出时间2.1.5.日志内容2.1.6.日志输出对象2.1.7.线程名称 2.2.logback.xml修改日志输出…

Java网络编程之TCP协议核心机制(二)

目录 题外话 正题 滑动窗口机制 如果出现丢包问题怎么办?? 滑动窗口触发条件 流量控制 拥塞控制 小结 题外话 宿舍没有空调的感觉谁懂?!!! 人要蒸发了,八点自动热醒,直接强行学习 正题 我们继续讲解TCP协议核心机制 上篇博客讲完了,建立连接机制,确认应答机制,超时…

Boxy SVG for Mac:打造精致矢量图形的得力助手

在矢量图形设计领域&#xff0c;Boxy SVG for Mac以其出色的性能和丰富的功能&#xff0c;成为了设计师们的得力助手。 Boxy SVG for Mac(矢量图编辑器) v4.32.0免激活版下载 Boxy SVG具备强大的编辑能力&#xff0c;支持节点编辑、路径绘制、颜色填充等多种操作&#xff0c;让…

struct.unpack_from()学习笔记

struct.unpack_from(fmt,b_data,offset) 按照指定的格式fmt&#xff0c;从偏移位置offset&#xff0c;对b_data开始解包&#xff0c;返回数据格式是一个元组(v1,v2…) fmt可以有&#xff1a; _struct.py: The remaining chars indicate types of args and must match exactly;…