目录
[问题 1:我项目里从来没写 extends Thread / implements Runnable,为什么项目还是多线程?](#问题 1:我项目里从来没写 extends Thread / implements Runnable,为什么项目还是多线程?)
[问题 2:我不写线程代码,那我的接口是怎么多线程执行的?](#问题 2:我不写线程代码,那我的接口是怎么多线程执行的?)
[问题 3:请求很多,不会无限创建线程导致内存溢出吗?](#问题 3:请求很多,不会无限创建线程导致内存溢出吗?)
[模拟 Tomcat 线程池(你给的代码,标准示例)](#模拟 Tomcat 线程池(你给的代码,标准示例))
[输出结果(你会看到 3 个线程反复执行 5 个任务)](#输出结果(你会看到 3 个线程反复执行 5 个任务))
[问题 4:多线程会不会把我的数据搞乱?为什么局部变量不会乱?成员变量会乱?](#问题 4:多线程会不会把我的数据搞乱?为什么局部变量不会乱?成员变量会乱?)
[问题 5:我什么时候才需要自己写多线程?](#问题 5:我什么时候才需要自己写多线程?)
[问题 6:多线程到底提高了什么效率?](#问题 6:多线程到底提高了什么效率?)
一、真实开发最核心困惑
问题 1:我项目里从来没写 extends Thread / implements Runnable,为什么项目还是多线程?
回答
因为多线程 ≠ 你写线程代码 多线程 = 有线程调用你的代码
Tomcat / Spring 内部已经自带线程池,来一个请求,分配一个线程 。你的 Controller、Service 只是被线程调用的业务代码,不是线程本身。
最简单理解
线程 = 工人你的代码 = 桌子工人擦桌子 ≠ 桌子变成工人
问题 2:我不写线程代码,那我的接口是怎么多线程执行的?
回答
流程如下(Tomcat 自动完成):
- 用户发送请求
- Tomcat 线程池拿出一个空闲线程
- 线程调用你的
@GetMapping / @PostMapping - 执行完,线程归还线程池(复用)
示例代码(无任何线程代码)
java
@RestController
public class UserController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable Integer id){
// 这里运行在 Tomcat 线程里
return "用户id:" + id;
}
}
结论
你不写多线程 = 多线程依然存在 多线程是底层框架提供的。
二、线程池与内存安全困惑
问题 3:请求很多,不会无限创建线程导致内存溢出吗?
回答
绝对不会! 因为 Tomcat / Spring 使用线程池 ,线程固定数量、复用。
线程池特点
- 最多固定线程数(默认 200)
- 线程执行完任务不销毁,放回池子
- 来再多请求,也不会无限创建线程
- 单个栈内存 1MB,200 线程也就 200MB
模拟 Tomcat 线程池(你给的代码,标准示例)
java
// 模拟Tomcat线程池(真实开发由框架管理,无需我们写)
public class ThreadPoolTest {
public static void main(String[] args) {
// 线程池:最多3个线程,复用线程,不重复创建
ExecutorService pool = Executors.newFixedThreadPool(3);
// 提交5个任务,线程复用,不会创建5个线程
for (int i = 1; i <= 5; i++) {
int finalI = i;
pool.submit(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + ",执行任务" + finalI);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
pool.shutdown(); // 关闭线程池(真实开发中框架自动管理)
}
}
输出结果(你会看到 3 个线程反复执行 5 个任务)
线程:pool-1-thread-1,执行任务1
线程:pool-1-thread-2,执行任务2
线程:pool-1-thread-3,执行任务3
线程:pool-1-thread-1,执行任务4
线程:pool-1-thread-2,执行任务5
问题 4:多线程会不会把我的数据搞乱?为什么局部变量不会乱?成员变量会乱?
回答
内存规则:栈私有,堆共享
- 局部变量(在栈):每个线程独立,绝对安全
- 成员变量 / 静态变量(在堆):共享,会被线程抢占,不安全
代码案例:局部变量安全
java
@Service
public class UserService {
public void add(int num){
// 局部变量:线程独立,绝对安全
int i = 0;
i++;
}
}
代码案例:成员变量不安全(多线程会覆盖)
java
@Service
public class OrderService {
// 成员变量:共享!多线程会错乱
int count = 0;
public void add(){
count++;
}
}
三、真实开发必懂结论
问题 5:我什么时候才需要自己写多线程?
回答
只有以下场景需要:
- 异步发送短信 / 邮件
- 异步导出报表
- 异步处理日志
- 批量任务并行处理
普通接口完全不用写!
问题 6:多线程到底提高了什么效率?
回答
不是让代码变快,而是让 CPU 不等待。
- 单线程:遇到 IO / 网络 / 数据库,CPU 空转等死
- 多线程:CPU 切换去做别的任务
单位时间能处理更多请求 = 提高效率
四、终极总结(可直接背诵)
真实开发多线程核心结论
- 我不写线程代码 = 项目依然是多线程
- 多线程由 Tomcat / Spring 线程池提供
- 线程池固定数量、复用,不会内存溢出
- 局部变量安全,成员变量共享不安全
- 我只需要写业务,框架自动管理线程