feat:增加SpringBoot 线程与事件文档
This commit is contained in:
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