333 lines
8.6 KiB
Markdown
333 lines
8.6 KiB
Markdown
---
|
||
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() + " 监听到事件,发放优惠券");
|
||
}
|
||
}
|
||
``` |