很久没有发贴了,最近在做大量数据处理的项目,是一种IO密集型项目。一般我们是采用的普通多线程的方式进行处理,效率感觉也不是很快。cpu好像也到了极限,内存也不是占用很大。【这里面其实还有一个问题就是我们的CPU其实很大有96核心,同事表示貌似没有吃透这块原理,他没想着去调大我们的核心线程池大小,而是去在一个服务器上部署了多个节点,这种我认为是有问题的,感觉这是跟k8s部署多节点有混淆的意思。】,以下是我基于简单的创建虚拟线程和解决上面【】里面事情做的记录。
直接上虚拟线程:
package com.game.game21.virtual;
public class VirtualThread {
public static void main(String[] args) throws InterruptedException {
var t=Thread.ofVirtual().start(() -> {
System.out.println("Virtual Thread");
});
/* var executors = Executors.newVirtualThreadPerTaskExecutor();
executors.submit(() -> {
//异步任务,这里的参数不用lambda表达式的话要传一个实现Runnable的类
});*/
t.join();
}
}
package com.game.game21.virtual;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class VirtualThrad3 {
public static void main(String[] args) throws InterruptedException {
// 创建一个使用虚拟线程的线程池
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 提交1000个任务
for (int i = 0; i < 1000; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed by " + Thread.currentThread());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return taskId;
});
}
} // 线程池会自动关闭
}
}
在 Java 21+ 中引入的虚拟线程(Virtual Threads)与传统线程池有一些重要区别,特别是在线程池大小设置方面。
虚拟线程池的特点
- 不需要设置线程池大小:虚拟线程的设计初衷就是可以创建大量(数百万)轻量级线程,而不需要像平台线程(传统线程)那样担心资源耗尽问题。
- 资源管理方式不同:虚拟线程由 JVM 管理,在底层使用少量的平台线程作为载体线程(carrier threads)。
为什么不需要设置大小
- 虚拟线程非常轻量(内存开销约几百字节)
- 阻塞操作不会占用载体线程(当虚拟线程阻塞时,载体线程可以执行其他虚拟线程)
- JVM 会自动管理载体线程池(通常是CPU核心数大小的ForkJoinPool)
最佳实践
虽然不需要设置虚拟线程池大小,但可以考虑以下方面:
- 限制并发任务数量:如果担心资源消耗(如数据库连接),可以使用信号量(Semaphore)限制并发数
java
复制
下载
try (var semaphore = new Semaphore(100)) { // 限制100并发
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < 10_000; i++) {
semaphore.acquire();
futures.add(executor.submit(() -> {
try {
// 任务代码
} finally {
semaphore.release();
}
}));
}
}- 载体线程池配置:可以通过系统属性调整载体线程池大小(通常不需要)
- jdk.virtualThreadScheduler.parallelism - 并行度(默认是CPU核心数)
- jdk.virtualThreadScheduler.maxPoolSize - 最大池大小
与传统线程池对比
特性 | 虚拟线程池 | 传统线程池 |
线程开销 | 极小(几百字节) | 较大(约1MB) |
阻塞影响 | 几乎无影响 | 占用线程 |
池大小 | 不需要设置 | 需要谨慎设置 |
适用场景 | 高并发I/O密集型 | CPU密集型 |
总结:使用虚拟线程时,通常不需要也不应该设置线程池大小,这是虚拟线程的主要优势之一。
