Java19新特性-虚拟线程(第一次预览)

一、为什么引入虚拟线程

你在某天接到老板的任务,写一个简单的需求:前端传一个 fileId 过来,需要去文件服务器下载下来并解析,然后针对解析的内容做一些xxx的事情,需求很简单,你三下五除二就搞定了:

    public void doSomething(String fileId) {
        String filePath = downloadFile(Field);
        List<XxxDTO> list = readFile(filePath);
        doSomething(list);
    }

随着业务增长,请求量越来越大,此接口响应速度越来越慢了,而这个时候你又恰好学习了多线程,知道多线程能够提高系统吞吐量,然后小试牛刀一把:

    public void doSomething(String fileId) {
        new Thread(()->{
            String filePath = downloadFile(Field);
            List<XxxDTO> list = readFile(filePath);
            doSomething(list);
        }).start();
    }

但是在测试环境压测时,测试同学测着测着发现不对劲了,怎么越搞越慢,而且内存都快爆表了,你只好请教旁边的 Java 高手了,高手一看,惊呆了,大惊:小伙子,不错啊,会用线程了,但不是你这么搞的,去请测试吃顿饭吧,否则年底你要背绩效了。高手告诉你:你这样一个请求创建一个线程,成本很高,资源会被耗尽的,你要池化。然后你又花了一个晚上学习了线程池,改造如下:

    public void doSomething(String fileId) {
        executor.submit(() -> {
            String filePath = downloadFile(Field);
            List<XxxDTO> list = readFile(filePath);
            doSomething(list);
        });
    }

这段代码足够顶很长时间了。但是架不住公司快速发展,某天老板跟你说,它的那个接口还需要优化下。你懵逼了,这还怎么优化啊?只有硬着头皮去找高手帮助了,高手跟你说,你这个接口是 I/O 密集型接口,主要耗时在下载文件和读取文件上,所以要针对它们做优化。大明哥告诉你,刚刚好项目组已完成 Java 21 版本的升级(虚拟线程在 Java 19 为预览特性 ,Java 21 转正),里面有一个虚拟线程是处理I/O密集型操作的神器

二、什么是虚拟线程

众所周知,JVM 是一个多线程环境,它通过 java.lang.Thread 为我们提供了对操作系统线程的抽象,但是 Java 中的线程都只是对操作系统线程的一种简单封装,我们可以称之为“平台线程”。

然后,就平台线程而言,在某些场景下,它是有一些缺陷的,具体体现在:

  • 代价昂贵:创建平台线程的成本很高。每当创建一个平台线程时,操作系统都必须在堆栈中分配大量内存来存储线程的上下文、原生调用堆栈和 Java 调用堆栈。由于堆栈大小是固定的,这就导致了高昂的内存开销。
  • 上下文切换成本高:在多线程环境下,需要在不同线程间切换,这种上下文切换会消耗时间和资源。
  • 线程数量有限:Java 线程仅仅只是对操作系统线程的封装,而操作系统线程的数量是有限的,这就限制了 Java 同时运行的线程数量,从而限制了应用程序的并发能力。

然后虚拟线程就没有这个烦恼。

那什么是虚拟线程呢?

虚拟线程是 Java 中的一种轻量级线程,它旨在解决传统线程模型中的一些限制,提供了更高效的并发处理能力,允许创建数千甚至数万个虚拟线程,而无需占用大量操作系统资源。


虚拟线程是 JDK 而不是 OS 实现的轻量级线程(Lightweight Process,LWP),由 JVM 调度。许多虚拟线程共享同一个操作系统线程,虚拟线程的数量可以远大于操作系统线程的数量。

虚拟线程与传统线程具有如下几个优势:

  1. 更加轻量级:虚拟线程相比传统线程更加轻量级。因为它们不是直接映射到操作系统线程上,而是在用户空间内被管理。这种设计减少了线程创建和销毁的开销,允许在同一应用中运行成千上万的线程。【虚拟线程(Virtual Thread-)是 JDK 而不是 OS 实现的轻量级线程(Lightweight Process,LWP),许多虚拟线程共享同一个操作系统线程,虚拟线程的数量可以远大于操作系统线程的数量。】
  2. 资源消耗更少:由于不是直接映射到操作系统线程,虚拟线程显著降低了内存和其他资源的消耗。这使得在有限资源下可以创建更多的线程。
  3. 上下文切换开销更低:由于虚拟线程在用户空间,而不是通过操作系统,所以它的上下文切换开销更低。
  4. 改善阻塞操作的处理:在传统线程模型中,阻塞操作(如 I/O)会导致整个线程被阻塞,浪费宝贵的系统资源。然而当一个虚拟线程阻塞时,它可以被挂起,底层的操作系统线程则可以用来运行其他虚拟线程。
  5. 简化并发编程:可以像编写普通顺序代码一样编写并发代码,而不需要过多考虑线程管理和调度。它简化了 Java 的并发编程模型。
  6. 提升性能:在 I/O 密集型应用中,虚拟线程能够显著地提升性能。而且由于它们的创建和销毁成本低,能够更加高效地利用系统资源。

虽然虚拟线程这么厉害,但是它不做以下几件事:

  • 不替代传统线程:虚拟线程并不旨在完全替代传统的操作系统线程,而是作为一个补充。对于需要密集计算和精细控制线程行为的场景,传统线程仍然是主流。
  • 非针对最低延迟:虚拟线程主要针对高并发和高吞吐量,而不是最低延迟。对于需要极低延迟的应用,传统线程可能是更好的选择。
  • 不改变基本的线程模型:虚拟线程改进了线程的实现方式,但并未改变Java基本的线程模型和同步机制。锁和同步仍然是并发控制的重要工具。

在引入虚拟线程之前,java.lang.Thread 包已经支持所谓的平台线程(Platform Thread),也就是没有虚拟线程之前,我们一直使用的线程。JVM 调度程序通过平台线程(载体线程)来管理虚拟线程,一个平台线程可以在不同的时间执行不同的虚拟线程(多个虚拟线程挂载在一个平台线程上),当虚拟线程被阻塞或等待时,平台线程可以切换到执行另一个虚拟线程。虚拟线程、平台线程和系统内核线程的关系图如下所示:
在这里插入图片描述

三、如何使用虚拟线程

虚拟线程的使用和普通线程几乎一模一样,他们唯一区别在于创建虚拟线程只能通过特定的方法。

一、Thread.startVirtualThread() 创建

创建虚拟线程最简单的方式就是使用 Thread.startVirtualThread(Runnable)startVirtualThread() 是 Thread 静态方法,它用于创建一个新的虚拟线程,并立即执行给定的 Runnable 任务。

    @Test
    public void virtualThreadTest() {
   
        Thread.startVirtualThread(() -> {
   
            // 这里放置你的任务代码
            System.out.println("Java 19 新特性:虚拟线程");
        });
    } 

二、使用 Thread.ofVirtual()创建

Thread.ofVirtual() 是一个流式API,用于构

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悬浮海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值