Files
blog-press/docs/Web/SpringBoot/SpringBoot-Thread.md

8.6 KiB
Raw Permalink Blame History

title, date
title date
SpringBoot 线程与事件 2026-06-02

一、基本概念

进程:进程是操作系统资源分配的最小单位,每个进程都有独立的内存空间(代码段、数据段、堆、栈),比如打开一个应用程序,就是一个进程。
线程:线程是 CPU 调度的最小单位,线程共享所属进程的内存空间。 比如一个HTTP请求就是一个线程。
协程:协程是 用户态的轻量级“线程”,由程序自己调度,不依赖操作系统,切换成本极低。
  创建线程方法:

// 继承 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线程池:

// 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 共享资源

/**
 * 商品库存(共享资源)
 */
public class Stock {
    // 假设只有 1 件库存
    public int count = 1;
    // 信号:是否有人下单成功
    public volatile boolean ordered = false;
}

2.2 下单线程

/**
 * 用户下单线程
 */
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 消息分发线程

/**
 * 消息分发线程
 * 负责监听下单成功信号,并启动线程池发通知
 */
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 主程序

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 配置线程池

@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 订单服务

@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 通知服务

@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 定义事件

public class OrderCreatedEvent {
    private final String orderId;

    public OrderCreatedEvent(String orderId) {
        this.orderId = orderId;
    }

    public String getOrderId() {
        return orderId;
    }
}

4.2 发布事件

@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 监听事件

@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() + " 监听到事件,发放优惠券");
    }
}