You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JEP444中虚拟线程何时扩容底层载体线程?求代码示例

虚拟线程扩容底层载体线程的场景与代码示例

根据JEP 444的描述,虚拟线程的调度器(基于ForkJoinPool)会在虚拟线程导致底层载体OS线程被阻塞且无法被JVM调度机制接管的场景下,临时扩容并行度来补偿。具体场景及代码示例如下:

1. 同步IO阻塞场景

当虚拟线程执行java.io包下的同步IO操作(如文件读取、Socket同步通信)时,这些操作会直接阻塞底层OS线程,虚拟线程无法被JVM调度器主动切换。此时调度器会临时扩展并行度,新增载体线程来处理其他等待的虚拟线程。

import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.Executors;

public class VirtualThreadIOBlock {
    public static void main(String[] args) throws InterruptedException {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            // 提交100个执行同步文件读取的虚拟线程
            for (int i = 0; i < 100; i++) {
                executor.submit(() -> {
                    try (var fis = new FileInputStream("large-file.txt")) {
                        byte[] buffer = new byte[1024];
                        // 阻塞式读取文件,占用载体线程
                        while (fis.read(buffer) != -1) {
                            // 模拟数据处理
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return null;
                });
            }
            // 等待所有任务完成
            Thread.sleep(10000);
        }
    }
}

说明:多个虚拟线程同时执行同步IO时,每个阻塞的IO操作会占用一个载体线程,调度器自动扩容载体线程数量,避免其他虚拟线程长时间等待。

2. 持有synchronized锁时的阻塞场景

synchronized是基于OS线程的监视器锁,虚拟线程进入synchronized块/方法后会被固定到当前载体线程,直到退出同步块。如果此时该载体线程因同步IO、JNI调用等操作被阻塞,调度器会临时扩容并行度来补偿。

import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.Executors;

public class VirtualThreadSyncBlock {
    private static final Object LOCK = new Object();

    public static void main(String[] args) throws InterruptedException {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 100; i++) {
                executor.submit(() -> {
                    synchronized (LOCK) {
                        try (var fis = new FileInputStream("large-file.txt")) {
                            byte[] buffer = new byte[1024];
                            // 同步IO阻塞,此时载体线程被占用
                            while (fis.read(buffer) != -1) {}
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    return null;
                });
            }
            Thread.sleep(10000);
        }
    }
}

说明:虚拟线程在synchronized块内执行阻塞操作时,载体线程被固定且无法处理其他虚拟线程,调度器会新增载体线程维持整体执行效率。

3. JNI/JNA阻塞调用场景

如果虚拟线程调用了阻塞的JNI/JNA方法,底层载体线程会被本地代码阻塞,JVM无法通过虚拟线程调度机制切换该载体线程,因此调度器会临时扩容并行度,分配新的载体线程。

import java.util.concurrent.Executors;

public class VirtualThreadJNI {
    // 加载包含阻塞JNI方法的本地库
    static {
        System.loadLibrary("blocking-native-lib");
    }

    // 声明阻塞的JNI方法
    private native void blockingNativeCall();

    public static void main(String[] args) throws InterruptedException {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 50; i++) {
                executor.submit(() -> {
                    // 调用阻塞的JNI方法,占用载体线程
                    new VirtualThreadJNI().blockingNativeCall();
                    return null;
                });
            }
            Thread.sleep(15000);
        }
    }
}

说明:JNI调用会绕过JVM的虚拟线程调度,阻塞载体线程,调度器通过扩容保证其他虚拟线程的执行不受影响。

内容的提问来源于stack exchange,提问作者FlyChenKai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:00:56