feat:增加SpringBoot 线程与事件文档
This commit is contained in:
@@ -18,18 +18,19 @@ export const routers = [
|
|||||||
{
|
{
|
||||||
text: '🍃 SpringBoot',
|
text: '🍃 SpringBoot',
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Spring IOC简介', link: '/Web/SpringBoot/SpringIOC' },
|
{ text: 'Spring IOC简介', link: '/Web/SpringBoot/Spring-IOC' },
|
||||||
{ text: 'Spring AOP简介', link: '/Web/SpringBoot/SpringAOP' },
|
{ text: 'Spring AOP简介', link: '/Web/SpringBoot/Spring-AOP' },
|
||||||
{ text: 'SpringBoot启动流程', link: '/Web/SpringBoot/SpringBoot-Start-Process' },
|
{ text: 'SpringBoot启动流程', link: '/Web/SpringBoot/SpringBoot-Start-Process' },
|
||||||
{ text: 'Spring MVC简介', link: '/Web/SpringBoot/SpringMVC' },
|
{ text: 'Spring MVC简介', link: '/Web/SpringBoot/Spring-MVC' },
|
||||||
{ text: 'SpringBoot Starter原理', link: '/Web/SpringBoot/SpringBootStarter' },
|
{ text: 'SpringBoot Starter原理', link: '/Web/SpringBoot/SpringBoot-Starter' },
|
||||||
{ text: 'SpringBoot Bean简介', link: '/Web/SpringBoot/SpringBootBean' },
|
{ text: 'SpringBoot Bean简介', link: '/Web/SpringBoot/SpringBoot-Bean' },
|
||||||
{ text: 'SpringBoot注解', link: '/Web/SpringBoot/SpringBoot-Annotation' },
|
{ text: 'SpringBoot注解', link: '/Web/SpringBoot/SpringBoot-Annotation' },
|
||||||
{ text: 'SpringBoot3原生镜像', link: '/Web/SpringBoot/SpringBoot3-GraalVM' },
|
{ text: 'SpringBoot3原生镜像', link: '/Web/SpringBoot/SpringBoot3-GraalVM' },
|
||||||
{ text: 'SpringBoot技巧', link: '/Web/SpringBoot/SpringBoot-Skills' },
|
{ text: 'SpringBoot技巧', link: '/Web/SpringBoot/SpringBoot-Skills' },
|
||||||
{ text: 'SpringBoot Common', link: '/Web/SpringBoot/SpringBoot-Common' },
|
{ text: 'SpringBoot Common', link: '/Web/SpringBoot/SpringBoot-Common' },
|
||||||
{ text: 'SpringBoot RestClient简介', link: '/Web/SpringBoot/SpringBoot-RestClient' },
|
{ text: 'SpringBoot RestClient简介', link: '/Web/SpringBoot/SpringBoot-RestClient' },
|
||||||
{ text: 'SpringBoot Redis简介和使用', link: '/Web/SpringBoot/SpringBoot-Redis' }
|
{ text: 'SpringBoot Redis简介和使用', link: '/Web/SpringBoot/SpringBoot-Redis' },
|
||||||
|
{ text: 'SpringBoot 线程与事件', link: '/Web/SpringBoot/SpringBoot-Thread' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
333
docs/Web/SpringBoot/SpringBoot-Thread.md
Normal file
333
docs/Web/SpringBoot/SpringBoot-Thread.md
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
---
|
||||||
|
title: SpringBoot 线程与事件
|
||||||
|
date: 2026-06-02
|
||||||
|
---
|
||||||
|
|
||||||
|
# 一、基本概念
|
||||||
|
  **进程**:进程是操作系统资源分配的最小单位,每个进程都有独立的内存空间(代码段、数据段、堆、栈),比如打开一个应用程序,就是一个进程。
|
||||||
|
  **线程**:线程是 CPU 调度的最小单位,线程共享所属进程的内存空间。 比如一个HTTP请求就是一个线程。
|
||||||
|
  **协程**:协程是 用户态的轻量级“线程”,由程序自己调度,不依赖操作系统,切换成本极低。
|
||||||
|
  创建线程方法:
|
||||||
|
```java
|
||||||
|
// 继承 Thread 不推荐
|
||||||
|
class MyThread extends Thread {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("线程运行中:" + Thread.currentThread().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Test {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
MyThread t = new MyThread();
|
||||||
|
t.start(); // ✅ 启动线程
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实现 Runnable
|
||||||
|
class MyRunnable implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("线程运行中:" + Thread.currentThread().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Test2 {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Thread t = new Thread(new MyRunnable());
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lambda 写法
|
||||||
|
Thread t = new Thread(() -> {
|
||||||
|
System.out.println("Hello Thread");
|
||||||
|
});
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
// 线程池
|
||||||
|
ThreadPoolExecutor executor = new ThreadPoolExecutor(
|
||||||
|
2, // 核心线程数
|
||||||
|
4, // 最大线程数
|
||||||
|
60,
|
||||||
|
TimeUnit.SECONDS,
|
||||||
|
new LinkedBlockingQueue<>(100),
|
||||||
|
Executors.defaultThreadFactory(),
|
||||||
|
new ThreadPoolExecutor.AbortPolicy()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
  **SpringBoot线程池**:
|
||||||
|
```java
|
||||||
|
// 1. 启动类加上 @EnableAsync 注解
|
||||||
|
@EnableAsync
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 线程池配置
|
||||||
|
@Bean
|
||||||
|
public Executor taskExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setCorePoolSize(5);
|
||||||
|
executor.setMaxPoolSize(10);
|
||||||
|
executor.setQueueCapacity(20);
|
||||||
|
executor.initialize();
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 调用方法上加上 @Async 注解
|
||||||
|
@Service
|
||||||
|
public class OrderService {
|
||||||
|
|
||||||
|
@Async
|
||||||
|
public void createOrder() {
|
||||||
|
System.out.println(Thread.currentThread().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 二、案例
|
||||||
|
  案例:电商秒杀系统。
|
||||||
|
- 资源竞争:多个用户抢同一件商品(多线程抢锁)。
|
||||||
|
- 异步解耦:扣减库存后,需要发短信、发优惠券(多线程并行)。
|
||||||
|
- 系统解耦:订单系统不应依赖短信系统(事件驱动)。
|
||||||
|
|
||||||
|
# 二、JDK原生线程通信
|
||||||
|
- synchronized:锁住库存,防止超卖。
|
||||||
|
- wait/notify:通知消息线程“库存已扣,可以发通知了”。
|
||||||
|
- Thread+ ExecutorService:实现多线程并行发通知。
|
||||||
|
|
||||||
|
## 2.1 共享资源
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 商品库存(共享资源)
|
||||||
|
*/
|
||||||
|
public class Stock {
|
||||||
|
// 假设只有 1 件库存
|
||||||
|
public int count = 1;
|
||||||
|
// 信号:是否有人下单成功
|
||||||
|
public volatile boolean ordered = false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2.2 下单线程
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 用户下单线程
|
||||||
|
*/
|
||||||
|
public class OrderWorker extends Thread {
|
||||||
|
|
||||||
|
private final Stock stock;
|
||||||
|
|
||||||
|
public OrderWorker(Stock stock) {
|
||||||
|
this.stock = stock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// 1. 锁住库存,防止超卖
|
||||||
|
synchronized (stock) {
|
||||||
|
if (stock.count > 0) {
|
||||||
|
System.out.println(Thread.currentThread().getName() + " 抢到锁,准备扣库存");
|
||||||
|
stock.count--;
|
||||||
|
stock.ordered = true;
|
||||||
|
System.out.println("库存扣减成功,剩余:" + stock.count);
|
||||||
|
stock.notifyAll(); // 通知消息线程
|
||||||
|
} else {
|
||||||
|
System.out.println(Thread.currentThread().getName() + " 没抢到,库存不足");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2.3 消息分发线程
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 消息分发线程
|
||||||
|
* 负责监听下单成功信号,并启动线程池发通知
|
||||||
|
*/
|
||||||
|
public class MessageDispatcher extends Thread {
|
||||||
|
|
||||||
|
private final Stock stock;
|
||||||
|
private final ExecutorService pool;
|
||||||
|
|
||||||
|
public MessageDispatcher(Stock stock, ExecutorService pool) {
|
||||||
|
this.stock = stock;
|
||||||
|
this.pool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
synchronized (stock) {
|
||||||
|
try {
|
||||||
|
while (!stock.ordered) {
|
||||||
|
System.out.println("消息线程:等待下单信号...");
|
||||||
|
stock.wait(); // 没下单就死等
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("消息线程:收到下单成功信号,开始并行发通知!");
|
||||||
|
|
||||||
|
// 2. 并行执行通知任务
|
||||||
|
pool.execute(() -> System.out.println("线程池任务:发送短信"));
|
||||||
|
pool.execute(() -> System.out.println("线程池任务:发放优惠券"));
|
||||||
|
pool.execute(() -> System.out.println("线程池任务:更新用户积分"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2.4 主程序
|
||||||
|
```java
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class TraditionalDemo {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Stock stock = new Stock();
|
||||||
|
ExecutorService pool = Executors.newFixedThreadPool(3);
|
||||||
|
|
||||||
|
// 消息线程先启动(等待)
|
||||||
|
new MessageDispatcher(stock, pool).start();
|
||||||
|
|
||||||
|
// 模拟 3 个用户同时下单(竞争)
|
||||||
|
new OrderWorker(stock).start();
|
||||||
|
new OrderWorker(stock).start();
|
||||||
|
new OrderWorker(stock).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 三、SpringBoot 异步方法
|
||||||
|
- @Transactional:保证库存扣减的事务性。
|
||||||
|
- @Async:将发短信、发券等耗时操作丢给线程池,立即释放 Tomcat 线程。
|
||||||
|
|
||||||
|
## 3.1 配置线程池
|
||||||
|
```java
|
||||||
|
@Configuration
|
||||||
|
@EnableAsync
|
||||||
|
public class AsyncConfig {
|
||||||
|
|
||||||
|
@Bean("orderExecutor")
|
||||||
|
public Executor orderExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setCorePoolSize(5);
|
||||||
|
executor.setThreadNamePrefix("Order-Async-");
|
||||||
|
executor.initialize();
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3.2 订单服务
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
public class OrderService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StockService stockService;
|
||||||
|
@Autowired
|
||||||
|
private NotifyService notifyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下单主流程
|
||||||
|
*/
|
||||||
|
public void createOrder() {
|
||||||
|
// 1. 扣库存(核心,同步)
|
||||||
|
boolean success = stockService.decreaseStock();
|
||||||
|
if (!success) {
|
||||||
|
throw new RuntimeException("库存不足");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 异步通知(非核心,并行)
|
||||||
|
notifyService.sendSms();
|
||||||
|
notifyService.sendCoupon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3.3 通知服务
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
public class NotifyService {
|
||||||
|
|
||||||
|
// 指定使用哪个线程池
|
||||||
|
@Async("orderExecutor")
|
||||||
|
public void sendSms() {
|
||||||
|
System.out.println(Thread.currentThread().getName() + " 发送短信");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async("orderExecutor")
|
||||||
|
public void sendCoupon() {
|
||||||
|
System.out.println(Thread.currentThread().getName() + " 发放优惠券");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 四、SpringBoot 事件机制
|
||||||
|
- 事件(Event):下单成功这个“事实”。
|
||||||
|
- 发布者(Publisher):只负责发布事件,不关心后续。
|
||||||
|
- 监听者(Listener):谁关心下单成功,谁就干活(且可以异步)。
|
||||||
|
|
||||||
|
## 4.1 定义事件
|
||||||
|
```java
|
||||||
|
public class OrderCreatedEvent {
|
||||||
|
private final String orderId;
|
||||||
|
|
||||||
|
public OrderCreatedEvent(String orderId) {
|
||||||
|
this.orderId = orderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrderId() {
|
||||||
|
return orderId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4.2 发布事件
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
public class OrderService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StockService stockService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationEventPublisher publisher;
|
||||||
|
|
||||||
|
public void createOrder() {
|
||||||
|
// 1. 扣库存
|
||||||
|
boolean success = stockService.decreaseStock();
|
||||||
|
if (success) {
|
||||||
|
// 2. 发布事件(我不关心谁处理)
|
||||||
|
publisher.publishEvent(new OrderCreatedEvent("ORDER_123"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4.3 监听事件
|
||||||
|
```java
|
||||||
|
@Component
|
||||||
|
public class OrderListener {
|
||||||
|
|
||||||
|
// 监听下单事件,并异步执行
|
||||||
|
@EventListener
|
||||||
|
@Async("orderExecutor")
|
||||||
|
public void handleSendSms(OrderCreatedEvent event) {
|
||||||
|
System.out.println(Thread.currentThread().getName() + " 监听到事件,发送短信");
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
@Async("orderExecutor")
|
||||||
|
public void handleSendCoupon(OrderCreatedEvent event) {
|
||||||
|
System.out.println(Thread.currentThread().getName() + " 监听到事件,发放优惠券");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user