学习网站的建设,广告投放方案,锐旗网站建设,国内网站建设公司JDK 21 中引入的虚拟线程是 Java 并发生态系统的一个重要里程碑。本文将介绍虚拟线程的基础知识和最佳实践。 什么是虚拟线程#xff1f;
多线程是业界广泛用于开发基于 Java 的应用程序的特性。它允许我们并行运行操作#xff0c;从而加快任务执行速度。任何 Java 应用程序…JDK 21 中引入的虚拟线程是 Java 并发生态系统的一个重要里程碑。本文将介绍虚拟线程的基础知识和最佳实践。什么是虚拟线程多线程是业界广泛用于开发基于 Java 的应用程序的特性。它允许我们并行运行操作从而加快任务执行速度。任何 Java 应用程序创建的线程数量都受限于操作系统能够处理的并行操作数量 换句话说Java 应用程序中的线程数量等于操作系统线程的数量。考虑到当前快速发展的生态系统这一限制一直是应用程序进一步扩展的瓶颈。为了克服这一限制Java 在 JDK 21 中引入了虚拟线程的概念。Java 应用程序创建一个虚拟线程该线程不与任何操作系统线程关联。这意味着每个虚拟线程都不需要依赖于平台线程即操作系统线程。虚拟线程可以独立处理任何任务并且仅在需要执行 I/O 操作时才会获取平台线程。这种获取和释放平台线程的机制使应用程序能够灵活地创建尽可能多的虚拟线程从而实现高并发性。1,JDK 21 之前的线程在 JDK 21 之前所有java.lang.Thread 类的实例都是操作系统线程也称为平台线程。这意味着在 JDK 环境中创建的每个线程都必须映射到一个平台线程。这种机制限制了 JVM 环境中可创建的线程数量。由于创建平台线程的成本很高过去通常会使用线程池来避免重复创建线程但这会增加应用程序的性能开销。2,JDK 21 之后的线程在 JDK 21 中应用程序开发人员可以选择使用Thread.ofVirtual() API 或 Executors.newVirtualThreadPerTaskExecutor() 创建虚拟线程而不是平台线程。以这种方式创建的线程在 JVM 内部运行不会占用任何操作系统线程。虚拟线程可以像平台线程一样执行所有并发任务。虚拟线程需要平台线程来执行 I/O 操作I/O 操作完成后虚拟线程会释放平台线程。虚拟线程不需要线程池管理。由于它们是 JVM 内部的因此系统中可以拥有无限数量的虚拟线程。为什么需要虚拟线程高吞吐量包含大量并发操作的任务例如服务器应用程序会花费大量时间等待。Web 服务器通常需要处理大量客户端请求。如果没有虚拟线程它们处理并行请求的能力将受到限制。使用虚拟线程可以处理大量并发请求从而提升服务器的处理能力。无需线程池虚拟线程资源占用低可用性高因此无需使用线程池。对于每个并发任务我们都可以创建一个虚拟线程这就像在 JVM 内存中创建一个对象一样简单。高性能创建虚拟线程耗时更少因为无需操作系统级别的操作因此可以提升应用程序的整体性能。更低的内存消耗每个虚拟线程都在堆中维护一个栈用于存储局部变量和方法调用。每个虚拟线程可以创建多个子线程并且这些子线程的生命周期很短因此每个线程的调用栈都很浅内存消耗极低。可扩展解决方案API密集型应用程序通常采用每个请求一个线程的设计方式。由于虚拟线程允许JVM创建比平台线程更多的线程因此应用程序可以扩展以服务大量客户端请求。如何创建虚拟线程当前的 JDK 框架支持两种创建虚拟线程的方法。以下是创建虚拟线程的示例代码。方法一使用 接口Thread.Builder builder Thread.ofVirtual().name(NewThread); Runnable task () - { System.out.println(Running thread); }; Thread t builder.start(task); System.out.println(Thread name: t.getName());方法二: 框架try (ExecutorService myExecutor Executors.newVirtualThreadPerTaskExecutor()) { Future? future myExecutor.submit(() - System.out.println(Running a new thread)); future.get(); System.out.println(Task completed);性能对比虚拟线程 vs 平台线程我创建了一个简单的程序来展示虚拟线程和平台线程之间的性能差异。代码片段//Store 类用于存储由奇数和偶数生成的线程数。它使用并发哈希映射来存储这些数据。 public class Store { private ConcurrentHashMapInteger, Integer concurrentHashMap new ConcurrentHashMapInteger, Integer(); public synchronized void addQuantity(int productId){ int key productId % 2; concurrentHashMap.computeIfAbsent(key,k-0); concurrentHashMap.computeIfPresent(key,(k,v)-v1); } public MapInteger, Integer getStoreData(){ return concurrentHashMap; } }//这个类充当一个任务由多个线程执行。每个线程都有一个任务即递增存储中的计数。 public class ComputationTask implements Runnable{ int productId; Store store; public ComputationTask(Store store, int id){ this.store store; productIdid; } Override public void run() { store.addQuantity(productId); }//这个主类包含实例化虚拟线程和平台线程的逻辑。它会创建超过 1000 个线程所有线程完成工作后代码会打印哈希映射条目以及整个进程所花费的总时间。 public class Main { public static void main(String[] args) throws InterruptedException { long pid ProcessHandle.current().pid(); System.out.println(Process ID: pid); Thread.Builder builder null; Store store new Store(); builder Thread.ofVirtual().name(virtual worker-, 0); // builder Thread.ofPlatform().name(platform worker-, 0); long starttime System.currentTimeMillis(); for (int i 1; i 1000; i) { ComputationTask task new ComputationTask(store, i); Thread t1 builder.start(task); t1.join(); System.out.println(t1.getName() started); } MapInteger,Integer map store.getStoreData(); map.entrySet().stream() .forEach(entry - System.out.println(Key: entry.getKey() , Value: entry.getValue())); long endtime System.currentTimeMillis(); System.out.println(Total Computation Time - (endtime-starttime) miliseconds); } }执行结果使用虚拟线程执行程序virtual worker-0 started virtual worker-1 started virtual worker-2 started virtual worker-3 started …………………………………. …………………………………. virtual worker-995 started virtual worker-996 started virtual worker-997 started virtual worker-998 started virtual worker-999 started Key: 0, Value: 500 Key: 1, Value: 500 Total Computation Time - 147 miliseconds Process finished with exit code 0使用平台线程执行程序。注释掉虚拟线程在 Main.java 中创建代码然后取消注释创建平台线程的代码。platform worker-0 started platform worker-1 started platform worker-2 started platform worker-3 started …………………………………….. …………………………………….. platform worker-995 started platform worker-996 started platform worker-997 started platform worker-998 started platform worker-999 started Key: 0, Value: 500 Key: 1, Value: 500 Total Computation Time - 551 miliseconds Process finished with exit code 0根据上述结果可知当程序创建 1000 个虚拟线程并执行特定操作时耗时 147 毫秒而相同的代码如果使用平台线程运行则大约需要 551 毫秒才能完成。因此虚拟线程比平台线程具有更好的性能。使用虚拟线程的最佳实践虚拟线程仅在执行同步代码块时才会绑定到平台线程。因此应避免频繁且持续时间长的同步代码块以缩短平台线程的生命周期从而充分利用虚拟线程模型。切勿创建虚拟线程池因为虚拟线程数量庞大创建新的虚拟线程开销很小。如果没有线程池JVM 就不需要处理复杂的逻辑来维护线程池和进行调度。避免使用异步代码编写技术因为在同步代码中服务器会为每个传入的请求分配一个线程并持续处理整个请求周期。由于虚拟线程数量众多阻塞它们的开销很小因此值得鼓励。虚拟线程支持线程局部变量。但是由于虚拟线程数量可能很多因此应谨慎使用线程局部变量。不要使用线程局部变量来在线程池中共享同一线程的多个任务之间分配昂贵的资源。