引入:
1. 虚拟线程是挂载到平台线程(载体线程)中去的,在遇到阻塞时,载体线程将会从阻塞的虚拟线程进行卸载,虚拟线程阻塞结束,载体线程会挂载到空闲的载体线程上。
2. 虚拟线程与平台线程相比,有轻量化特点,更小,支持的并发量更多。
3. 无需池化,直接即可创建,设计的目标就是避免池化。
坑点:
1. 任务中使用 synchronized 包裹的代码则遇到阻塞会进行无法释放虚拟线程。
创建虚拟线程的方式:
1.创建虚拟线程,并且指定一个Name
// 创建并启动一个虚拟线程 Thread vt = Thread.ofVirtual() .name("my-vt-", 0) // 可选:设置名称前缀和起始编号 .start(() -> { System.out.println("Running in virtual thread"); System.out.println("Is virtual: " + Thread.currentThread().isVirtual()); }); vt.join(); // 等待完成2. 直接创建虚拟线程,书写任务逻辑
// 一行代码创建并启动 Thread vt = Thread.startVirtualThread(() -> { System.out.println("Hello from virtual thread!"); }); vt.join();3. 提交的任务都创建一个虚拟线程(虚拟线程执行器)
// 每个提交的任务都会获得一个新的虚拟线程 try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { executor.submit(() -> { Thread.sleep(Duration.ofSeconds(1)); return i; }) } // try-with-resources 自动关闭,等待所有任务完成拓展使用:
1. 使用Callable进行规划任务逻辑,使用虚拟线程执行器进行执行代码逻辑,汇总返回结果。
private static void virtualThread3() { System.out.println("创建virtualThread"); long start = System.currentTimeMillis(); List<Callable<String>> tasks = List.of( () -> { for (int i = 0; i < 100; i++) { System.out.println("任务1 正在被 [" + Thread.currentThread() + "] 执行"); } // ✅ 在这里打印,看看是谁在执行我 return callUserService(); }, () -> { for (int i = 0; i < 100; i++) { System.out.println("任务2 正在被 [" + Thread.currentThread() + "] 执行"); } return callUserService(); }, () -> { for (int i = 0; i < 100; i++) { System.out.println("任务3 正在被 [" + Thread.currentThread() + "] 执行"); } return callUserService(); } ); try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { List<Future<String>> futures = executor.invokeAll(tasks); futures.stream().forEach(System.out::println); futures.stream() .map(f -> { try { return f.get(); // 此时任务已完成,get() 不会阻塞 } catch (Exception e) { throw new CompletionException(e); } }) .toList(); } catch (Exception e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("Time taken: " + (end - start) / 1000 + " 秒"); System.out.println("CPU Cores: " + Runtime.getRuntime().availableProcessors()); }2. 使用CompletableFuture 指定虚拟线程方式进行启动
private static void virtualThread5() { System.out.println("创建 virtualThread (CompletableFuture)"); long start = System.currentTimeMillis(); ExecutorService vtExecutor = Executors.newVirtualThreadPerTaskExecutor(); // 每个任务独立提交,返回 CompletableFuture CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> { for (int i = 0; i < 100; i++) System.out.println("任务1 [" + Thread.currentThread() + "]"); try { return callUserService(); } catch (InterruptedException e) { throw new RuntimeException(e); } }, vtExecutor); // <--- 指定虚拟线程执行器 CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> { for (int i = 0; i < 100; i++) System.out.println("任务2 [" + Thread.currentThread() + "]"); try { return callUserService(); } catch (InterruptedException e) { throw new RuntimeException(e); } }, vtExecutor); CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> { for (int i = 0; i < 100; i++) System.out.println("任务3 [" + Thread.currentThread() + "]"); try { return callUserService(); } catch (InterruptedException e) { throw new RuntimeException(e); } }, vtExecutor); try { // 等待所有任务完成并收集结果 List<String> results = CompletableFuture.allOf(f1, f2, f3) .thenApply(v -> List.of(f1.join(), f2.join(), f3.join())) .join(); // 主线程阻塞等待 System.out.println("Results: " + results); } finally { vtExecutor.close(); // try-with-resources 也可以,这里手动演示 } System.out.println("Time taken: " + (System.currentTimeMillis() - start) / 1000 + " 秒"); }3. 配合信号量使用
private static void virtualThread4() throws RuntimeException { final Semaphore DB_LIMITER = new Semaphore(50); try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { //先拿锁 executor.submit(() -> { try { DB_LIMITER.acquire(); //业务逻辑xxx callUserService(); } catch (InterruptedException e) { //释放锁 DB_LIMITER.release(); } }); } }