|
|
## Spring 任务线程池 vs Tomcat 线程池
### 核心区别
| 特性 | Tomcat 线程池 | Spring 任务线程池 |
|------|--------------|------------------|
| **用途** | 处理 HTTP 请求 | 执行异步任务 `@Async` |
| **触发方式** | 外部 HTTP 请求触发 | 代码主动调用 |
| **线程名前缀** | `http-nio-端口-exec-` | `MyAsyncThread-`(自定义) |
| **配置位置** | `server.tomcat.threads.*` | 自定义 `task-executor.*` |
| **阻塞影响** | 阻塞会导致请求超时 | 阻塞只影响异步任务 |
---
### 工作流程图
```
┌─────────────────────────────────────────┐
│ Spring Boot 应用 │
│ │
HTTP 请求 ──────────► │ ┌─────────────────────────────────┐ │
│ │ Tomcat 线程池 │ │
│ │ http-nio-9999-exec-1~10 │ │
│ │ │ │
│ │ 处理: @GetMapping, @PostMapping │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ │ 调用 @Async 方法 │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ Spring 任务线程池 │ │
│ │ MyAsyncThread-1~500 │ │
│ │ │ │
│ │ 处理: Redis操作, 耗时任务 │ │
│ └─────────────────────────────────┘ │
│ │
└─────────────────────────────────────────┘
```
---
### 你的代码中的实际流程
```java
// 1. HTTP 请求进入,由 Tomcat 线程处理
@PutMapping("/string") // ← http-nio-9999-exec-3 处理
public ResponseEntity<Map<String, Object>> putString(...) {
// 2. 调用异步服务,提交到 Spring 线程池
CompletableFuture<Boolean> future = redisAsyncService.putStringAsync(key, body, ttlSec);
// ↑
// MyAsyncThread-1 执行
// 3. Tomcat 线程等待结果
Boolean ok = future.get(asyncTimeout, TimeUnit.SECONDS);
// 4. 返回响应
return ResponseEntity.ok(res);
}
// Spring 任务线程池执行
@Async("redisExecutor") // ← MyAsyncThread-1 处理
public CompletableFuture<Boolean> putStringAsync(String key, String value, Long ttlSec) {
stringRedisTemplate.opsForValue().set(key, value);
return CompletableFuture.completedFuture(true);
}
```
---
### 配置对比
```yaml
# Tomcat 线程池配置
server:
port: 9999
tomcat:
threads:
max: 200 # 最大线程数
min-spare: 10 # 核心线程数
accept-count: 100 # 等待队列
# Spring 任务线程池配置
task-executor:
core_pool_size: 16 # 核心线程数
max_pool_size: 500 # 最大线程数
queue_capacity: 5000 # 队列大小
keep_alive_seconds: 60 # 空闲时间
name_prefix: MyAsyncThread-
```
---
### 日志对比
```log
# Tomcat 线程处理 HTTP 请求
2025-12-24 07:02:33 [http-nio-9999-exec-3] PUT STRING key=xxx
# Spring 异步线程执行任务
2025-12-24 07:02:33 [MyAsyncThread-1] Redis write success, key=xxx
```
---
### 为什么需要两个线程池?
| 场景 | 只用 Tomcat 线程池 | Tomcat + Spring 线程池 |
|------|-------------------|----------------------|
| **10个请求同时来** | 10个线程全部阻塞在 Redis | Tomcat 线程快速返回 |
| **Redis 慢** | 请求堆积,新请求超时 | 异步任务排队,HTTP 正常响应 |
| **高并发** | 容易耗尽线程 | 分层处理,更抗压 |
---
### 联系
```
HTTP 请求
│
▼
┌─────────────────────────────┐
│ Tomcat 线程池 │
│ http-nio-9999-exec-X │
│ │
│ 职责: │
│ - 接收 HTTP 请求 │
│ - 参数校验 │
│ - 调用业务逻辑 │
│ - 返回 HTTP 响应 │
└──────────────┬──────────────┘
│
│ @Async 调用
▼
┌─────────────────────────────┐
│ Spring 任务线程池 │
│ MyAsyncThread-X │
│ │
│ 职责: │
│ - Redis 读写 │
│ - 文件 I/O │
│ - 耗时计算 │
│ - 异步通知 │
└─────────────────────────────┘
```
---
### 配置建议
```yaml
# 推荐配置
server:
tomcat:
threads:
max: 200 # HTTP 处理,不需要太多
min-spare: 20
task-executor:
core_pool_size: 32 # Redis 操作多,可以大一些
max_pool_size: 200
queue_capacity: 10000
keep_alive_seconds: 60
name_prefix: RedisAsync-
```
---
### 总结
| 问题 | 答案 |
|------|------|
| **Tomcat 线程池** | 处理 HTTP 请求入口 |
| **Spring 任务线程池** | 执行 `@Async` 异步任务 |
| **联系** | Tomcat 线程调用 `@Async` 方法,提交到 Spring 线程池 |
| **区别** | 职责不同,互不影响 |
| **建议** | 分开配置,根据业务调整 |
|
|