java21新特性:虚拟线程

前排提示:本文引用了大佬JavaGuide的博客

1.什么是虚拟线程?

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

2.虚拟线程的优点和缺点

优点

  • 非常轻量级:可以在单个线程中创建成百上千个虚拟线程而不会导致过多的线程创建和上下文切换。
  • 简化异步编程: 虚拟线程可以简化异步编程,使代码更易于理解和维护。它可以将异步代码编写得更像同步代码,避免了回调地狱(Callback Hell)。
  • 减少资源开销: 相比于操作系统线程,虚拟线程的资源开销更小。本质上是提高了线程的执行效率,从而减少线程资源的创建和上下文切换。

缺点

  • 不适用于计算密集型任务: 虚拟线程适用于 I/O 密集型任务,但不适用于计算密集型任务,因为密集型计算始终需要 CPU 资源作为支持。
  • 依赖于语言或库的支持: 协程需要编程语言或库提供支持。不是所有编程语言都原生支持协程。比如 Java 实现的虚拟线程。

3.四种创建虚拟线程的方法

Java 21 已经正式支持虚拟线程,大家可以在官网下载使用,在使用上官方为了降低使用门槛,尽量复用原有的 Thread 类,让大家可以更加平滑的使用。

官方提供了以下四种方式创建虚拟线程:

  1. 使用 Thread.startVirtualThread() 创建
  2. 使用 Thread.ofVirtual() 创建
  3. 使用 ThreadFactory 创建
  4. 使用 Executors.newVirtualThreadPerTaskExecutor()创建

1.使用 Thread.startVirtualThread()创建

typescript 复制代码
public class VirtualThreadTest { 
  public static void main(String[] args) { 
    CustomThread customThread = new CustomThread();
    Thread.startVirtualThread(customThread); 
  }
}

static class CustomThread implements Runnable { 
  @Override 
  public void run() { 
    System.out.println("CustomThread run"); 
  } 
}

2.使用 Thread.ofVirtual()创建

typescript 复制代码
public class VirtualThreadTest {  
  public static void main(String[] args) { 
    CustomThread customThread = new CustomThread();
    // 创建不启动
    Thread unStarted = Thread.ofVirtual().unstarted(customThread);
    unStarted.start(); 
    // 创建直接启动
    Thread.ofVirtual().start(customThread); 
  }
}
static class CustomThread implements Runnable { 
  @Override
  public void run() { 
    System.out.println("CustomThread run"); 
  }
}

3. 使用 ThreadFactory 创建

java 复制代码
public class VirtualThreadTest { 
  public static void main(String[] args) { 
    CustomThread customThread = new CustomThread();
    ThreadFactory factory = Thread.ofVirtual().factory();
    Thread thread = factory.newThread(customThread);
    thread.start(); 
  }
}

static class CustomThread implements Runnable {
  @Override
  public void run() {
    System.out.println("CustomThread run");
  }
}

4.使用 Executors.newVirtualThreadPerTaskExecutor()创建

typescript 复制代码
public class VirtualThreadTest {
  public static void main(String[] args) {
    CustomThread customThread = new CustomThread();
    ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
    executor.submit(customThread);
  }
}
static class CustomThread implements Runnable {
  @Override
  public void run() {
    System.out.println("CustomThread run");
  } 
}

4.虚拟线程和平台线程性能对比

通过多线程和虚拟线程的方式处理相同的任务,对比创建的系统线程数和处理耗时。

说明:统计创建的系统线程中部分为后台线程(比如 GC 线程),两种场景下都一样,所以并不影响对比。

测试代码

ini 复制代码
public class VirtualThreadTest {
    static List<Integer> list = new ArrayList<>();
    public static void main(String[] args) {
        // 开启线程 统计平台线程数
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
            ThreadInfo[] threadInfo = threadBean.dumpAllThreads(false, false);
            updateMaxThreadNum(threadInfo.length);
        }, 10, 10, TimeUnit.MILLISECONDS);

        long start = System.currentTimeMillis();
        // 虚拟线程
        ExecutorService executor =  Executors.newVirtualThreadPerTaskExecutor();
        // 使用平台线程
        // ExecutorService executor =  Executors.newFixedThreadPool(200);
        for (int i = 0; i < 10000; i++) {
            executor.submit(() -> {
                try {
                    // 线程睡眠 0.5 s,模拟业务处理
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException ignored) {
                }
            });
        }
        executor.close();
        System.out.println("max:" + list.get(0) + " platform thread/os thread");
        System.out.printf("totalMillis:%dms\n", System.currentTimeMillis() - start);


    }
    // 更新创建的平台最大线程数
    private static void updateMaxThreadNum(int num) {
        if (list.isEmpty()) {
            list.add(num);
        } else {
            Integer integer = list.get(0);
            if (num > integer) {
                list.add(0, num);
            }
        }
    }
}

请求数 10000 单请求耗时 1s

arduino 复制代码
// Virtual Thread
max:22 platform thread/os thread
totalMillis:1806ms

// Platform Thread  线程数200
max:209 platform thread/os thread
totalMillis:50578ms

// Platform Thread  线程数500
max:509 platform thread/os thread
totalMillis:20254ms

// Platform Thread  线程数1000
max:1009 platform thread/os thread
totalMillis:10214ms

// Platform Thread  线程数2000
max:2009 platform thread/os thread
totalMillis:5358ms
  • 可以看到在密集 IO 的场景下,需要创建大量的平台线程异步处理才能达到虚拟线程的处理速度。
  • 因此,在密集 IO 的场景,虚拟线程可以大幅提高线程的执行效率,减少线程资源的创建以及上下文切换。
相关推荐
一只爱打拳的程序猿10 分钟前
【Spring】更加简单的将对象存入Spring中并使用
java·后端·spring
杨荧12 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
minDuck14 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
为将者,自当识天晓地。33 分钟前
c++多线程
java·开发语言
daqinzl41 分钟前
java获取机器ip、mac
java·mac·ip
激流丶1 小时前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
Themberfue1 小时前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
让学习成为一种生活方式1 小时前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
晨曦_子画1 小时前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
南宫生2 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法