我对Java Web开发中多线程的困惑

目录

一、真实开发最核心困惑

[问题 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 自动完成):

  1. 用户发送请求
  2. Tomcat 线程池拿出一个空闲线程
  3. 线程调用你的 @GetMapping / @PostMapping
  4. 执行完,线程归还线程池(复用)

示例代码(无任何线程代码)

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 切换去做别的任务

单位时间能处理更多请求 = 提高效率


四、终极总结(可直接背诵)

真实开发多线程核心结论

  1. 我不写线程代码 = 项目依然是多线程
  2. 多线程由 Tomcat / Spring 线程池提供
  3. 线程池固定数量、复用,不会内存溢出
  4. 局部变量安全,成员变量共享不安全
  5. 我只需要写业务,框架自动管理线程
相关推荐
Evand J4 小时前
【MATLAB例程】多无人机协同巡逻仿真:基于长机-僚机模型的编队保持与串级PID控制
开发语言·matlab·无人机·控制·pid·串级pid
xiufeia4 小时前
JMeter
java·jmeter·tomcat·高并发
周淳APP4 小时前
【React之Hooks原理、组件、状态管理浅谈】
开发语言·前端·javascript
楼田莉子4 小时前
CMake学习:CMake在静态库工程场景上应用
开发语言·c++·后端·学习·软件构建
断春风4 小时前
深入了解 Java 日志框架:SLF4J 和 Logback
java·架构·logback
csbysj20204 小时前
SVG 渐变 - 线性
开发语言
迷藏4944 小时前
**发散创新:用 Rust实现高效共识算法——从 Raft到自研轻量级协议的实战演进**
java·开发语言·rust·共识算法
wuqingshun3141594 小时前
说说你对spring MVC的理解
java·开发语言·jvm