自学内容网 自学内容网

【java21】java21新特性之虚拟线程

Java21中引入的虚拟线程(Virtual Threads)是一项重要的新特性,它为Java并发编程带来了革命性的改进。

虚拟线程,也称为用户模式线程(user-mode threads)或纤程(fibers),是Java21中引入的一种轻量级线程实现方式。这一特性旨在简化并发编程,提供更好的可扩展性,并大幅提升Java的并发能力。随着企业应用的规模不断壮大,大量的网络请求或读写I/O场景越来越多,虚拟线程的引入对于I/O密集型程序的性能带来了大幅度的提升。

虚拟线程的工作原理

虚拟线程基于操作系统级别的线程(传统Java线程),但由JVM(Java虚拟机)进行调度和管理。它不会在整个生命周期内都占用一个操作系统线程,而是多个虚拟线程可以在一个操作系统线程上运行。这种设计减少了线程调度的开销,并允许创建大量的虚拟线程而不会占用大量操作系统资源。

具体来说,JDK先将虚拟线程分配给平台线程(即操作系统线程),然后平台线程按照通常的方式由操作系统进行调度。JDK的虚拟线程调度器是一个以FIFO(先进先出)模式运行的ForkJoinPool,它负责管理和调度虚拟线程的执行。

虚拟线程的优势

  • 轻量级:虚拟线程的创建、销毁和切换开销比操作系统级别的线程更小,因此可以创建大量的虚拟线程来支持更高的并发度。
  • 高效并发:虚拟线程在用户级别进行线程调度和管理,提供了更高的可控性,并大幅提升了Java的并发能力。
  • 资源优化:由于虚拟线程是基于操作系统线程的优化,它可以在不增加操作系统资源消耗的情况下,提高应用程序的性能。

虚拟线程的使用场景

  • 高并发、低延迟应用:如金融应用服务器可以利用虚拟线程实现多线程业务逻辑,提高交易响应的流畅度和响应速度。
  • Web应用:可以使用虚拟线程来处理高并发的HTTP请求,提高Web服务器的吞吐量和响应速度。
  • 大数据处理:在大数据处理场景中,可以使用虚拟线程来处理海量数据,提高数据处理速度和效率。

虚拟线程的创建与使用

在Java21中,创建和使用虚拟线程有多种方法,包括:

  • 使用Thread.startVirtualThread方法:该方法接受一个Runnable对象作为参数,并立即启动一个新的虚拟线程来执行该Runnable对象中的代码。
  • 使用Thread.ofVirtual方法:该方法可以创建一个虚拟线程的构建器,允许设置线程名称等属性,并通过调用start方法启动虚拟线程。
  • 使用ExecutorService:Java21中引入了新的ExecutorService来适配虚拟线程,可以使用Executors.newVirtualThreadPerTaskExecutor方法创建一个为每个提交的任务创建虚拟线程的ExecutorService。
package com.morris.java21;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 虚拟线程的使用
 */
public class VirtualThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        // 使用Thread.startVirtualThread方法
        Thread thread = Thread.startVirtualThread(() -> {
            System.out.println(Thread.currentThread().getName());
            System.out.println("Hello from virtual thread 1!");
            try {
                Thread.sleep(1000); // 模拟一些工作
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println("Done by virtual thread 1!");
        });

        Thread.ofVirtual().name("virtual-thread")
                .start(() -> System.out.println(Thread.currentThread().getName() + "start with Thread.ofVirtual()"));

        // 使用ExecutorService
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
        executor.submit(() -> {
            System.out.println("Hello from virtual thread 2 via ExecutorService!");
            // 你的并发任务代码
        });
        executor.shutdown(); // 注意:这不会立即关闭执行器,它会等待所有任务完成或超时。
        thread.join(); // 要等待执行完,虚拟线程是守护线程,不等待的话就退出了
    }
}

可以使用jstack查看虚拟线程:

"VirtualThread-unparker" #30 [9156] daemon prio=5 os_prio=0 cpu=0.00ms elapsed=20.43s tid=0x0000020d3a2387b0 nid=9156 waiting on condition  [0x000000b56c8fe000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at jdk.internal.misc.Unsafe.park(java.base@21.0.3/Native Method)
        - parking to wait for  <0x000000071556e6a0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(java.base@21.0.3/LockSupport.java:269)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(java.base@21.0.3/AbstractQueuedSynchronizer.java:1758)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@21.0.3/ScheduledThreadPoolExecutor.java:1182)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@21.0.3/ScheduledThreadPoolExecutor.java:899)
        at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@21.0.3/ThreadPoolExecutor.java:1070)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@21.0.3/ThreadPoolExecutor.java:1130)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@21.0.3/ThreadPoolExecutor.java:642)
        at java.lang.Thread.runWith(java.base@21.0.3/Thread.java:1596)
        at java.lang.Thread.run(java.base@21.0.3/Thread.java:1583)
        at jdk.internal.misc.InnocuousThread.run(java.base@21.0.3/InnocuousThread.java:186)

注意事项

  • 线程安全:虚拟线程仍然存在竞争条件和死锁等问题,因此需要注意线程安全。
  • 内存管理:由于虚拟线程的上下文信息是与操作系统线程一起共享的,因此如果虚拟线程过多,且有的虚拟线程未正常关闭,可能会导致内存泄漏问题。因此,在虚拟线程的处理中要特别注意释放内存并关闭网络连接。
  • 性能评估:虽然虚拟线程在并发性和可扩展性方面提供了显著的帮助,但它们并不总是适合所有场景。有些需要大量计算的任务,并不一定在虚拟线程中运行得更好。因此,需要通过测试评测来找到最优解。

原文地址:https://blog.csdn.net/u022812849/article/details/142753825

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!