文章目录
线程池及其在Java中的使用:
1、线程复用: 线程池是一种限制和管理线程数量的机制,可以复用线程。
2、减少开销: 减少创建和销毁线程的性能开销。
3、使用方式: 通过Executor框架中的Executors类创建,例如Executors.newFixedThreadPool(), 但是强烈建议通过构造方法创建;
4、任务提交: 将实现了Runnable或Callable接口的任务提交给线程池执行。
一、什么是线程池?—— 线程的 “共享充电宝”
线程池是提前创建一批线程,统一管理、复用的 “线程容器”。
核心思想是:避免频繁创建 / 销毁线程(像反复买新手机充电,不如共享充电宝随取随用),通过复用现有线程处理任务,减少资源开销,提高并发效率。
为什么需要线程池?(痛点解决)
-
降低资源消耗: 创建线程需要分配栈内存(默认 1M)、内核资源,销毁线程也需回收资源,频繁操作会 “浪费电”;线程池复用线程,避免这些开销。
-
提高响应速度: 任务来了不用等线程创建,直接从池里拿 “空闲线程”,像拿共享充电宝不用等配送。
-
便于管理控制: 统一控制线程数量(避免线程太多导致 CPU 飙满、内存溢出)、任务排队规则、拒绝策略(任务太多时如何处理),像充电宝柜控制 “最大借出数”“排队规则”。
二、Java 中如何使用线程池?—— 3 种核心方式(从简单到灵活)
Java 线程池的核心接口是 ExecutorService,常用实现类是 ThreadPoolExecutor(推荐),还有 Executors 工具类(快速创建,但不推荐生产用)。
2.1 方式1: Executors 工具类 —— 快速 “开箱即用”(入门首选)
Executors 是 JDK 提供的 “线程池工厂”,封装了常用线程池类型,一行代码就能创建。但生产环境不推荐(存在 OOM 风险,后面说原因),适合学习 / 简单场景。
示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorsDemo {
public static void main(String[] args) {
// 1. 固定线程数线程池(核心线程数=最大线程数,无空闲线程超时)
// 场景:任务量稳定,避免线程频繁创建销毁(比如服务器接收请求)
ExecutorService fixedPool = Executors.newFixedThreadPool(3); // 3个“固定工人”
// 2. 缓存线程池(核心线程数=0,最大线程数=Integer.MAX_VALUE,空闲线程60秒销毁)
// 场景:任务量大但耗时短(比如临时计算、异步回调)
ExecutorService cachedPool = Executors.newCachedThreadPool(); // 无限“临时工”,60秒没活辞退
// 3. 单线程线程池(核心线程数=最大线程数=1,任务串行执行)
// 场景:需要任务按顺序执行(比如日志写入、数据库批量操作)
ExecutorService singlePool = Executors.newSingleThreadExecutor(); // 1个“专属工人”
// 提交任务(两种方式:Runnable无返回值,Callable有返回值)
for (int i = 1; i <= 5; i++) {
int taskNum = i;
// 方式1:提交Runnable任务(无返回值)
fixedPool.execute(() -> {
System.out.println("线程" + Thread.currentThread().getName() + "处理任务" + taskNum);
try {
Thread.sleep(1000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 方式2:提交Callable任务(有返回值,需用Future获取)
/*
Future<Integer> future = fixedPool.submit(() -> {
return 1 + 1; // 任务返回值
});
try {
System.out.println("任务结果:" + future.get()); // 阻塞获取结果
} catch (Exception e) {
e.printStackTrace();
}
*/
// 关闭线程池(必须关!否则JVM不会退出)
fixedPool.shutdown(); // 优雅关闭:等待已提交任务完成,不再接新任务
// fixedPool.shutdownNow(); // 强制关闭:立即中断正在执行的任务,返回未执行的任务
}
}
运行结果(固定线程池 3 个线程处理 5 个任务):
线程pool-1-thread-1处理任务1
线程pool-1-thread-2处理任务2
线程pool-1-thread-3处理任务3
线程pool-1-thread-1处理任务4(1秒后复用)
线程pool-1-thread-2处理任务5(1秒后复用)
2.2 ThreadPoolExecutor —— 手动创建(生产推荐,灵活可控)
Executors 的底层是 ThreadPoolExecutor,但它的参数是 “硬编码” 的(比如 newCachedThreadPool 最大线程数是 Integer.MAX_VALUE,任务多了会创建大量线程导致 OOM)。生产环境推荐手动创建 ThreadPoolExecutor,按需调整核心参数。
➡️ 1. 核心参数(7大参数, 必须懂!!!)
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数(正式工:即使空闲也不辞退,除非设置allowCoreThreadTimeOut)
int maximumPoolSize, // 最大线程数(正式工+临时工:线程池能容纳的最大线程数)
long keepAliveTime, // 空闲线程超时时间(临时工没活干多久被辞退;如果allowCoreThreadTimeOut=true,正式工也适用)
TimeUnit unit, // 超时时间单位(秒、毫秒等,TimeUnit.SECONDS)
BlockingQueue<Runnable> workQueue, // 工作队列(任务排队的地方:任务来了先放队列,队列满了才创建临时工)
ThreadFactory threadFactory, // 线程工厂(创建线程的方式,可自定义线程名、优先级等)
RejectedExecutionHandler handler // 拒绝策略(任务太多:队列满了+最大线程数也用完了,如何处理任务)
)
🚀 2. 打个比方(工厂工人团队)
| 参数 | 比喻 | 例子(3 个正式工 + 2 个临时工) |
|---|---|---|
| corePoolSize | 正式工数量 | 3 个正式工,即使没事做也不辞退 |
| maximumPoolSize | 最大工人总数(正 + 临) | 最多 5 个工人(3 正式 + 2 临时) |
| keepAliveTime | 临时工空闲超时时间 | 临时工没活干超过 10 秒,辞退 |
| workQueue | 任务等待队列 | 任务来了先放队列,队列满了(比如队列容量 5)才招临时工 |
| threadFactory | 招工工厂 | 给工人起名字(比如 “线程池 - 任务组 1 - 线程 1”) |
| handler | 任务拒绝策略 | 队列满 + 工人全忙时,新任务如何处理(比如 “告诉提交者干不了”) |
🎉3. 常用队列和拒绝策略
| 组件类型 | 常用实现 | 作用 |
|---|---|---|
| 工作队列 | ArrayBlockingQueue(有界) | 固定容量的队列(推荐!避免无界队列 OOM),比如 new ArrayBlockingQueue(10) |
| LinkedBlockingQueue(无界) | 无固定容量(不推荐!任务多了会 OOM),Executors.newFixedThreadPool 用它 | |
| 拒绝策略 | AbortPolicy(默认) | 抛出异常 RejectedExecutionException,告诉提交者 “任务被拒绝” |
| CallerRunsPolicy | 让提交任务的线程自己执行(比如主线程提交,主线程自己处理,缓解压力) | |
| DiscardPolicy | 直接丢弃任务,不抛异常(适合不重要的任务,比如日志) | |
| DiscardOldestPolicy | 丢弃队列中最老的任务,再提交新任务(适合 “最新任务优先” 场景) |
📌4. 生产级代码示例(自定义线程池 - 重点推荐)
import java.util.concurrent.*;
public class ThreadPoolExecutorDemo {
public static void main(String[] args) {
// 1. 自定义线程工厂(给线程起名字,方便排查问题)
ThreadFactory threadFactory = new ThreadFactory() {
private int count = 1;
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("业务线程池-线程" + count++); // 自定义线程名
thread.setDaemon(false); // 非守护线程(默认)
return thread;
}
};
// 2. 手动创建线程池(核心参数按需调整)
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
3, // 核心线程数:3个正式工
5, // 最大线程数:5个(3正+2临)
10, // 空闲超时时间:10秒
TimeUnit.SECONDS, // 时间单位:秒
new ArrayBlockingQueue<>(10), // 工作队列:容量10(有界,避免OOM)
threadFactory, // 线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:提交者自己执行
);
// 3. 提交15个任务(3正+2临+队列10=15,刚好处理;超过15会触发拒绝策略)
for (int i = 1; i <= 16; i++) { // 16个任务,触发拒绝策略
int taskNum = i;
threadPool.execute(() -> {
System.out.println("线程" + Thread.currentThread().getName() + "处理任务" + taskNum);
try {
Thread.sleep(1000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 4. 关闭线程池(优雅关闭,配合JVM钩子函数更佳)
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
threadPool.shutdown();
System.out.println("JVM退出,线程池已优雅关闭");
}));
}
}
运行结果(第 16 个任务触发拒绝策略,由主线程处理):
线程业务线程池-线程1处理任务1
线程业务线程池-线程2处理任务2
线程业务线程池-线程3处理任务3
线程业务线程池-线程4处理任务4(临时工1)
线程业务线程池-线程5处理任务5(临时工2)
线程业务线程池-线程1处理任务6(1秒后复用)
...(队列中的任务陆续被处理)
线程main处理任务16(主线程自己执行,拒绝策略生效)
2.3 Spring 框架的 ThreadPoolTaskExecutor —— 企业级首选(整合 Spring 生态)
如果项目用 Spring/Spring Boot,推荐用 ThreadPoolTaskExecutor(对 ThreadPoolExecutor 的封装,支持配置化、监控等),无需手动管理线程池生命周期。
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
// ....
}
✅ 1. Spring Boot配置(application.yml)
spring:
task:
execution:
pool:
core-size: 3 # 核心线程数
max-size: 5 # 最大线程数
keep-alive: 10s # 空闲超时时间
queue-capacity: 10 # 队列容量
allow-core-thread-timeout: false # 是否允许核心线程超时(默认false)
thread-name-prefix: "spring-task-" # 线程名前缀
🎀 2. 使用(直接注入即可)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Service
public class TaskService {
// 注入Spring管理的线程池
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
public void doTask() {
// 提交Runnable任务(无返回值)
taskExecutor.execute(() -> {
System.out.println("Spring线程池处理任务:" + Thread.currentThread().getName());
});
// 提交Callable任务(有返回值)
Future<Integer> future = taskExecutor.submit(() -> {
return 100 + 200;
});
try {
System.out.println("任务结果:" + future.get()); // 阻塞获取结果
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀
补充内容 - 虚拟线程结合线程池内容
🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀
三、虚拟线程 + 线程池:Java 并发的 “王炸组合”!
注意事项: JDK版本要求21, 目前Java已经到了25, 可放心使用;
如果说传统线程池是 “共享充电宝柜”(复用平台线程,减少资源开销),虚拟线程(JDK21 + 预览特性)就是 “可无限分发的一次性充电宝”(轻量级、创建成本趋近于 0)。两者结合,相当于 “充电宝柜里的每个插槽都能同时给 N 个设备充电”—— 既保留线程池的资源管控能力,又解锁虚拟线程的超高并发潜力,堪称 IO 密集场景的 “性能核弹”!
3.1 先搞懂:为啥要 “虚拟线程 + 线程池”?(单独用的痛点)
在聊结合之前,先明确单独用虚拟线程或传统线程池的 “坑”:
⬆️ 1. 单独用传统线程池(平台线程):并发上限低
传统线程池的线程是 “平台线程”(映射到操作系统内核线程),创建成本高(每个线程占 1M 栈内存)、数量有限(一般最多几百到几千个)。
比如 IO 密集场景(调用接口、查数据库),线程大部分时间在 “等响应”(阻塞),但线程池里的平台线程被占着,导致并发量上不去 —— 相当于 “充电宝柜只有 10 个插槽,10 个人在用,其他人只能排队,哪怕这 10 个人只是拿着充电宝没充电”。
✔️ 2. 单独使用虚拟线程: 资源失控风险
虚拟线程是 “用户态线程”(JVM 管理,不直接映射内核线程),创建成本极低(栈内存按需分配,可创建上百万个),但无限制创建会导致资源耗尽:
比如突然来了 100 万个请求,每个请求开一个虚拟线程,虽然虚拟线程本身轻量,但对应的任务队列、上下文切换还是会消耗 CPU 和内存 —— 相当于 “无限免费发充电宝,结果大家都堆在门口,导致通道堵塞”。
🗂️ 3. 结合的核心价值:1+1>2
- 线程池:负责 “资源管控”(比如限制最大并发的 “载体数”、任务排队、拒绝策略),避免无限制创建虚拟线程。
- 虚拟线程:负责 “高效执行”(IO 阻塞时自动挂起,释放载体线程给其他虚拟线程用),让线程池的 “载体” 利用率拉满。
比喻总结:线程池是 “快递站的货架”(限制最多放 10 个快递盒),虚拟线程是 “快递盒里的小包裹”(一个快递盒能装 100 个小包裹)—— 货架(线程池)控制总量,小包裹(虚拟线程)提升密度,最终快递站的处理能力暴涨!
四、底层逻辑: 虚拟线程 + 线程池的 “协作原理”
要理解结合的本质,先搞懂虚拟线程的核心特性:M:N 调度模型(M 个虚拟线程映射到 N 个平台线程)。
当虚拟线程执行 IO 操作(比如Thread.sleep()、Socket.read())阻塞时,JVM 会自动 “挂起” 这个虚拟线程,把对应的平台线程让给其他虚拟线程 —— 相当于 “你拿着充电宝没充电,快递站把充电宝暂时借给别人用,你要用时再还给你”。
而 “虚拟线程 + 线程池” 的协作流程是:
- 线程池管理少量平台线程(比如核心线程数 = CPU 核心数 ×2),作为 “载体线程”。
- 每个载体线程上,JVM 会调度大量虚拟线程(比如上万个)。
- 当某个虚拟线程阻塞(IO 等待),JVM 挂起它,让载体线程执行其他虚拟线程,直到阻塞结束再恢复。
核心优势:用少量平台线程(线程池管控),承载海量虚拟线程(高并发),IO 阻塞时不浪费载体资源 —— 相当于 “10 个货架(载体线程),每个货架放 1000 个小包裹(虚拟线程),总共能处理 1 万个包裹,远超单独用货架或单独堆包裹的能力”。

五、Java 中如何用?(3 种实战方式,从简单到生产)
JDK21 + 提供了专门支持虚拟线程的线程池 API,结合传统ThreadPoolExecutor也能实现,下面分场景讲解:
5.1 JDK 原生 “虚拟线程池” —— 快速入门
Executors.newVirtualThreadPerTaskExecutor ()
DK21 新增的Executors静态方法,直接创建 “每个任务一个虚拟线程” 的线程池,底层是ThreadPerTaskExecutor(特殊的线程池),语法极简,适合简单场景。
代码示例(IO 密集场景:调用第三方接口)
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class VirtualThreadPoolDemo1 {
public static void main(String[] args) throws InterruptedException {
// 1. 创建虚拟线程池:每个任务分配一个虚拟线程
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 2. 提交1000个IO密集型任务(模拟调用接口,每个任务阻塞1秒)
for (int i = 1; i <= 1000; i++) {
int taskNum = i;
executor.submit(() -> {
System.out.println("虚拟线程" + Thread.currentThread().getName() + "处理任务" + taskNum);
try {
// 模拟IO阻塞(比如调用接口、查数据库)
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
});
}
} // 3. try-with-resources自动关闭线程池,无需手动shutdown()
System.out.println("所有任务执行完毕(总耗时≈1秒,因为1000个虚拟线程并发执行)");
}
}
关键说明:
- 无需手动关闭线程池:newVirtualThreadPerTaskExecutor()返回的线程池实现了AutoCloseable,try-with-resources会自动关闭。
- 并发量爆炸:1000 个任务几乎同时执行,总耗时≈1 秒(因为虚拟线程阻塞时会释放载体线程,1000 个虚拟线程复用少量平台线程)。
- 适用场景:简单 IO 密集任务(比如异步回调、批量接口调用),无需复杂资源管控。
5.2 手动创建 “虚拟线程池” —— 生产首选
ThreadPoolExecutor + 虚拟线程工厂
newVirtualThreadPerTaskExecutor()是 “黑盒”,无法自定义核心参数(比如队列容量、拒绝策略)。
生产环境推荐用ThreadPoolExecutor手动创建,通过Thread.ofVirtual().factory()指定虚拟线程工厂,灵活管控资源。
核心参数设计(IO 密集场景):
- 核心线程数 / 最大线程数:建议设为CPU核心数×2(比如 8 核 CPU 设为 16),因为虚拟线程阻塞时会释放载体线程,不需要太多平台线程。
- 工作队列:用有界队列(比如ArrayBlockingQueue),避免任务过多导致 OOM。
- 线程工厂:Thread.ofVirtual().name(“biz-vt-”, 1).factory()(创建虚拟线程,自定义线程名)。
- 拒绝策略:根据业务选择(比如CallerRunsPolicy缓解压力)。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class VirtualThreadPoolDemo2 {
public static void main(String[] args) throws InterruptedException {
// 1. 虚拟线程工厂(自定义线程名,方便排查问题)
var threadFactory = Thread.ofVirtual()
.name("order-vt-", 1) // 线程名前缀:order-vt-1、order-vt-2...
.factory();
// 2. 手动创建虚拟线程池(核心参数按需调整)
var threadPool = new ThreadPoolExecutor(
16, // 核心线程数:16(8核CPU×2)
16, // 最大线程数:16(IO密集场景,核心=最大,避免创建临时工)
0, // 空闲超时时间:0(虚拟线程轻量,无需销毁)
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1000), // 有界队列:容量1000(避免OOM)
threadFactory, // 虚拟线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:提交者自己执行
);
// 3. 提交2000个IO密集任务(队列1000+线程16=1016,超过1016触发拒绝策略)
for (int i = 1; i <= 2000; i++) {
int taskNum = i;
threadPool.submit(() -> {
System.out.println("线程" + Thread.currentThread().getName() + "处理订单任务" + taskNum);
try {
// 模拟IO阻塞(比如查询订单数据库、调用支付接口)
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
});
}
// 4. 优雅关闭线程池(配合JVM钩子函数)
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
threadPool.shutdown();
try {
if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
threadPool.shutdownNow(); // 5秒后未关闭,强制关闭
}
System.out.println("应用退出,虚拟线程池已关闭");
} catch (InterruptedException e) {
threadPool.shutdownNow();
}
}));
// 等待任务执行(实际生产中无需手动等待,由应用生命周期管理)
threadPool.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("所有订单任务执行完毕");
}
}
关键说明:
- 重点阅读代码里的注释文字. 写的非常清楚了.
运行效果:
- 16 个平台线程(载体)承载 2000 个虚拟线程任务,总耗时≈(2000/16)×0.5 秒≈62.5 秒(如果用传统线程池,2000 个任务需要排队,总耗时≈2000×0.5 秒 = 1000 秒,差距巨大!)。
- 超过 1016 个任务时,触发拒绝策略,由提交线程(主线程)执行,避免任务丢失。
5.3 Spring Boot 整合虚拟线程池(企业级实战)
如果项目用 Spring Boot 3.2+(支持 JDK21+),可以直接通过配置启用虚拟线程池,无需手动创建,整合更丝滑。
✅ 1. 配置文件
spring:
task:
execution:
pool:
core-size: 16 # 核心线程数(平台线程数,IO密集=CPU×2)
max-size: 16 # 最大线程数(和核心一致,避免临时工)
keep-alive: 0s # 空闲超时时间(虚拟线程无需销毁)
queue-capacity: 1000 # 有界队列容量
thread-name-prefix: "spring-vt-" # 虚拟线程名前缀
virtual:
enabled: true # 启用虚拟线程池(关键!)
✔️ 2. 使用
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class OrderService {
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
// 异步处理订单(返回CompletableFuture,支持异步回调)
public CompletableFuture<Void> processOrder(int orderId) {
return CompletableFuture.runAsync(() -> {
System.out.println("虚拟线程" + Thread.currentThread().getName() + "处理订单" + orderId);
try {
// 模拟IO阻塞(调用支付接口、扣减库存)
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("订单处理失败", e);
}
}, taskExecutor);
}
}
控制器调用(Web 场景)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
// 接口并发测试:同时调用1000次,无压力
@GetMapping("/order/{id}")
public CompletableFuture<String> processOrder(@PathVariable int id) {
return orderService.processOrder(id)
.thenApply(v -> "订单" + id + "处理成功");
}
}
关键优势:
- Spring 自动管理虚拟线程池生命周期,无需手动关闭。
- 支持@Async注解(直接在方法上加@Async,无需手动提交任务)。
- 适配 Spring 生态(比如结合CompletableFuture、Spring Cloud异步调用)。
六、核心注意点(避坑指南,重中之重!)
6.1 虚拟线程只适合 “IO 密集型” 任务,不适合 “计算密集型”
- IO 密集型(推荐):调用接口、查数据库、文件 IO 等(线程大部分时间阻塞,虚拟线程能释放载体线程,提升并发)。
- 计算密集型(不推荐):数学计算、循环处理等(线程一直占用 CPU,虚拟线程挂起机制无用,反而增加 JVM 调度开销,不如用传统线程池 + CPU 核心数线程)。
6.2 线程池参数不能乱设(IO 密集场景最优配置)
| 参数 | 配置建议 | 原因 |
|---|---|---|
| 核心线程数 / 最大线程数 | CPU 核心数 ×2(比如 8 核 = 16) | 虚拟线程阻塞时释放载体,无需太多平台线程,多了反而增加上下文切换开销 |
| 工作队列 | 有界队列(比如ArrayBlockingQueue(1000)) | 无界队列会导致任务无限堆积,触发 OOM |
| 空闲超时时间 | 0 秒(或极短时间) | 虚拟线程轻量,无需销毁,保留载体线程复用即可 |
| 拒绝策略 | CallerRunsPolicy或自定义策略 | 虚拟线程并发高,拒绝策略需避免任务丢失,同时缓解系统压力 |
6.3 避免 “虚拟线程嵌套虚拟线程”
比如在一个虚拟线程里再创建一个虚拟线程池,会导致 JVM 调度复杂,性能下降 —— 相当于 “在一个小包裹里再塞 100 个小包裹,货架管理混乱”
6.4 监控虚拟线程状态(生产必备)
虚拟线程的状态可以通过Thread的 API 获取,结合监控工具(Prometheus+Grafana)告警:
// 获取线程池状态
System.out.println("活跃虚拟线程数:" + threadPool.getActiveCount());
System.out.println("队列等待任务数:" + threadPool.getQueue().size());
System.out.println("已完成任务数:" + threadPool.getCompletedTaskCount());
七、总结
- 线程池是 “线程复用容器”,核心优势是降低资源消耗、提高响应速度、便于管理。
- Java 使用线程池的 3 种方式:
- Executors:快速入门,不推荐生产用(OOM 风险)。
- ThreadPoolExecutor:手动创建,灵活可控,生产首选。
- ThreadPoolTaskExecutor:Spring 生态专用,企业级开发常用。
- 核心原则:用有界队列、合理设置线程数、选对拒绝策略、必须关闭线程池。
- 虚拟线程 + 线程池,IO 密集场景的 “性能天花板”
- 核心逻辑:线程池管 “载体”(平台线程),虚拟线程管 “任务”(高并发),利用 M:N 调度模型让 IO 阻塞时不浪费资源。
- 适用场景:接口调用、数据库操作、消息消费等 IO 密集型场景(并发量提升 10 倍 +,耗时大幅降低)。
- 不适用场景:纯计算任务(比如数据加密、复杂算法),不如传统线程池高效。
用一句热梗收尾:传统线程池是 “自行车队”(能拉货但慢),虚拟线程是 “电动车”(快但续航有限),两者结合是 “高铁”—— 又快又稳,还能拉满乘客(任务)!
950

被折叠的 条评论
为什么被折叠?



