高并发系统的核心骨架:生产者 - 消费者范式与线程池隔离的生产级落地全解

引言

在高并发业务场景中,系统的吞吐量、稳定性与可维护性,核心取决于异步解耦与故障隔离能力的落地。绝大多数线上高并发故障,本质都源于两个核心问题:一是同步调用导致的链路阻塞与响应超时,二是共用资源池引发的级联雪崩。生产者-消费者范式是异步解耦的核心骨架,线程池隔离则是故障隔离的黄金法则,二者结合,才能构建出能扛住百万级QPS、同时保证业务连续性的高并发系统。本文从底层原理到生产级代码实现,完整拆解这两个核心范式的落地逻辑,帮你彻底打通高并发编程的任督二脉。


一、生产者-消费者范式:从底层原理到生产级实现

1.1 范式的核心本质与业务价值

生产者-消费者是一种基于异步解耦的并发设计范式,核心是通过一个线程安全的中间缓冲区(队列),完全分离数据生产逻辑与数据消费逻辑。生产者仅需将数据写入缓冲区,无需关心消费逻辑的实现、执行时机与扩容策略;消费者仅需从缓冲区拉取数据处理,无需关心数据的生产来源与触发逻辑。

其核心业务价值集中在三点:

  1. 解耦:生产者与消费者无直接代码依赖,仅依赖缓冲区契约,双方可独立迭代、扩容与故障隔离,单一方异常不会直接导致全链路阻塞。

  2. 异步化:同步转异步,大幅缩短核心接口响应时长,将非核心逻辑从主链路剥离,提升用户体验。

  3. 削峰填谷:流量峰值期,生产者将请求写入缓冲区,消费者以固定处理能力匀速消费,避免峰值流量直接打垮下游数据库与第三方服务,是秒杀、大促场景的核心兜底能力。

1.2 底层线程通信机制全解析

生产者与消费者运行在不同线程中,必须解决线程间的同步与通信问题,避免出现数据丢失、重复消费、死锁与虚假唤醒等问题。Java中主流的线程通信机制分为三层,从底层原生实现到生产级封装逐层递进。

1.2.1 基于synchronized + wait/notify的原生实现

这是Java线程通信的底层基础,基于对象的监视器锁(Monitor)实现,JDK17中对synchronized做了全链路优化,从偏向锁、轻量级锁到重量级锁的自适应升级,性能已与显式Lock无显著差距。

核心规范(JDK官方强制要求):

  • wait()、notify()、notifyAll()必须在synchronized同步块内执行,否则会抛出IllegalMonitorStateException

  • wait()必须放在while循环中判断条件,禁止使用if判断,避免虚假唤醒导致的逻辑异常

  • 优先使用notifyAll()而非notify(),避免信号丢失导致的线程永久阻塞

    package com.jam.demo.base;
    import lombok.extern.slf4j.Slf4j;
    import java.util.LinkedList;
    import java.util.Queue;
    @Slf4j
    public class WaitNotifyModel {
    private final Queue buffer;
    private final int capacity;
    public WaitNotifyModel(int capacity) {
    this.buffer = new LinkedList<>();
    this.capacity = capacity;
    }
    /**
    * 生产者生产数据
    * @param data 待生产的数据
    * @throws InterruptedException 线程中断异常
    /
    public synchronized void produce(Object data) throws InterruptedException {
    while (buffer.size() == capacity) {
    this.wait();
    }
    buffer.offer(data);
    log.info("生产者生产数据,当前缓冲区大小:{}", buffer.size());
    this.notifyAll();
    }
    /
    *
    * 消费者消费数据
    * @return 消费的数据
    * @throws InterruptedException 线程中断异常
    */
    public synchronized Object consume() throws InterruptedException {
    while (buffer.isEmpty()) {
    this.wait();
    }
    Object data = buffer.poll();
    log.info("消费者消费数据,当前缓冲区大小:{}", buffer.size());
    this.notifyAll();
    return data;
    }
    }

    1.2.2 基于Lock + Condition的精准唤醒实现

    显式Lock与Condition组合,解决了synchronized只能有一个等待队列的缺陷,支持多条件队列实现精准唤醒,减少无效的线程上下文切换,底层基于JUC的AQS(抽象队列同步器)实现。

    核心优势:可分别创建生产者等待队列(notFull)与消费者等待队列(notEmpty),缓冲区满时仅阻塞生产者,缓冲区空时仅阻塞消费者,唤醒时仅唤醒对应队列的线程,无需全量唤醒。

    复制代码
    package com.jam.demo.base;
    import lombok.extern.slf4j.Slf4j;
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    @Slf4j
    public class LockConditionModel {
        private final Queue<Object> buffer;
        private final int capacity;
        private final Lock lock;
        private final Condition notFull;
        private final Condition notEmpty;
        public LockConditionModel(int capacity) {
            this.buffer = new LinkedList<>();
            this.capacity = capacity;
            this.lock = new ReentrantLock();
            this.notFull = lock.newCondition();
            this.notEmpty = lock.newCondition();
        }
        /**
         * 生产者生产数据
         * @param data 待生产的数据
         * @throws InterruptedException 线程中断异常
         */
        public void produce(Object data) throws InterruptedException {
            lock.lockInterruptibly();
            try {
                while (buffer.size() == capacity) {
                    notFull.await();
                }
                buffer.offer(data);
                log.info("生产者生产数据,当前缓冲区大小:{}", buffer.size());
                notEmpty.signal();
            } finally {
                lock.unlock();
            }
        }
        /**
         * 消费者消费数据
         * @return 消费的数据
         * @throws InterruptedException 线程中断异常
         */
        public Object consume() throws InterruptedException {
            lock.lockInterruptibly();
            try {
                while (buffer.isEmpty()) {
                    notEmpty.await();
                }
                Object data = buffer.poll();
                log.info("消费者消费数据,当前缓冲区大小:{}", buffer.size());
                notFull.signal();
                return data;
            } finally {
                lock.unlock();
            }
        }
    }
    1.2.3 基于JUC BlockingQueue的生产级封装

    生产环境99%的场景,无需手动实现线程同步逻辑,直接使用JUC提供的BlockingQueue阻塞队列即可,其内部已完整实现了线程同步、等待唤醒与内存可见性保证,是生产者-消费者范式的标准实现载体。

    核心特性:

    • 缓冲区满时,生产者线程自动阻塞,直到缓冲区出现空闲位置

    • 缓冲区空时,消费者线程自动阻塞,直到缓冲区写入新数据

    • 所有操作均为线程安全,无并发安全问题

    阻塞队列选型指南(生产级)
    队列实现类 底层结构 有界/无界 核心特性 生产适用场景
    ArrayBlockingQueue 定长数组 有界 单锁实现,读写不分离,支持公平锁,内存占用固定 容量固定的常规业务场景,严格控制内存占用
    LinkedBlockingQueue 链表 可选有界/无界 双锁实现,读写分离,吞吐量更高,默认无界(高危) 高吞吐量场景,必须强制指定容量
    SynchronousQueue 无缓冲 有界(容量0) 不存储元素,生产必须等待消费,一对一传递 短平快的无堆积任务场景,CachedThreadPool默认队列
    DelayQueue 优先级堆 无界 延迟消费,元素必须实现Delayed接口 超时订单关闭、定时任务重试、缓存过期清理
    PriorityBlockingQueue 二叉堆 无界 按优先级排序,支持自定义比较器 VIP订单优先处理、分级任务调度场景
    核心API选型规范

    BlockingQueue提供了四类操作API,生产环境需严格按场景选型,禁止乱用:

    操作类型 抛出异常 返回特殊值 无限阻塞 超时等待
    数据插入 add(e) offer(e) put(e) offer(e, timeout, unit)
    数据移除 remove() poll() take() poll(timeout, unit)
    数据查看 element() peek() 不支持 不支持

    生产环境强制规范:

    • 插入操作优先使用offer(e, timeout, unit),禁止无限阻塞的put(e),设置超时时间实现降级兜底,避免生产者线程永久阻塞

    • 移除操作优先使用poll(timeout, unit),禁止无限阻塞的take(),方便优雅停机与线程生命周期管理

    • 绝对禁止使用无界队列,除非能100%保证生产速度永远不超过消费速度,否则必然导致OOM

    1.3 生产级生产者-消费者完整实现

    以电商订单异步事件处理为场景,实现带优雅停机、异常重试、监控告警的生产级代码,基于JDK17编写,完整可运行。

    1.3.1 项目基础依赖(pom.xml)
    复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.4.0</version>
            <relativePath/>
        </parent>
        <groupId>com.jam</groupId>
        <artifactId>high-concurrency-demo</artifactId>
        <version>1.0.0</version>
        <name>high-concurrency-demo</name>
        <properties>
            <java.version>17</java.version>
            <guava.version>33.2.0-jre</guava.version>
            <fastjson2.version>2.0.53</fastjson2.version>
            <mybatis-plus.version>3.5.7</mybatis-plus.version>
            <springdoc.version>2.5.0</springdoc.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-validation</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springdoc</groupId>
                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
                <version>${springdoc.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.mysql</groupId>
                <artifactId>mysql-connector-j</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.34</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>${guava.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.fastjson2</groupId>
                <artifactId>fastjson2</artifactId>
                <version>${fastjson2.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    1.3.2 事件载体定义
    复制代码
    package com.jam.demo.model;
    import io.swagger.v3.oas.annotations.media.Schema;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import java.io.Serial;
    import java.io.Serializable;
    import java.time.LocalDateTime;
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Schema(description = "订单事件实体")
    public class OrderEvent implements Serializable {
        @Serial
        private static final long serialVersionUID = 1L;
        @Schema(description = "事件ID")
        private String eventId;
        @Schema(description = "订单号")
        private String orderNo;
        @Schema(description = "用户ID")
        private Long userId;
        @Schema(description = "事件类型")
        private String eventType;
        @Schema(description = "事件内容")
        private String content;
        @Schema(description = "重试次数")
        private Integer retryTimes;
        @Schema(description = "最大重试次数")
        private Integer maxRetryTimes;
        @Schema(description = "创建时间")
        private LocalDateTime createTime;
    }
    1.3.3 事件生产者实现
    复制代码
    package com.jam.demo.producer;
    import com.alibaba.fastjson2.JSON;
    import com.jam.demo.model.OrderEvent;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.TimeUnit;
    @Slf4j
    @Component
    public class OrderEventProducer {
        private static final int QUEUE_CAPACITY = 10000;
        private static final long OFFER_TIMEOUT = 3L;
        private final LinkedBlockingQueue<OrderEvent> eventQueue;
        public OrderEventProducer() {
            this.eventQueue = new LinkedBlockingQueue<>(QUEUE_CAPACITY);
        }
        /**
         * 投递订单事件到缓冲区
         * @param event 订单事件
         * @return 投递结果
         */
        public boolean sendEvent(OrderEvent event) {
            if (org.springframework.util.ObjectUtils.isEmpty(event)) {
                log.warn("订单事件为空,投递失败");
                return false;
            }
            try {
                boolean result = eventQueue.offer(event, OFFER_TIMEOUT, TimeUnit.SECONDS);
                if (result) {
                    log.info("订单事件投递成功,eventId:{},队列剩余容量:{}", event.getEventId(), eventQueue.remainingCapacity());
                } else {
                    log.error("订单事件投递超时,事件内容:{}", JSON.toJSONString(event));
                }
                return result;
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("订单事件投递被中断,eventId:{}", event.getEventId(), e);
                return false;
            }
        }
        /**
         * 从缓冲区拉取事件(供消费者调用)
         * @param timeout 超时时间
         * @param unit 时间单位
         * @return 订单事件
         * @throws InterruptedException 线程中断异常
         */
        public OrderEvent pollEvent(long timeout, TimeUnit unit) throws InterruptedException {
            return eventQueue.poll(timeout, unit);
        }
        /**
         * 获取当前队列积压数量
         * @return 积压事件数
         */
        public int getQueueSize() {
            return eventQueue.size();
        }
        /**
         * 获取队列剩余容量
         * @return 剩余容量
         */
        public int getRemainingCapacity() {
            return eventQueue.remainingCapacity();
        }
    }
    1.3.4 事件消费者实现
    复制代码
    package com.jam.demo.consumer;
    import com.jam.demo.model.OrderEvent;
    import com.jam.demo.producer.OrderEventProducer;
    import com.jam.demo.manager.ThreadPoolManager;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.stereotype.Component;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicBoolean;
    @Slf4j
    @Component
    public class OrderEventConsumer implements ApplicationRunner, DisposableBean {
        private static final int CONSUMER_THREAD_NUM = 4;
        private static final long POLL_TIMEOUT = 5L;
        private final OrderEventProducer orderEventProducer;
        private final ThreadPoolManager threadPoolManager;
        private final AtomicBoolean isRunning = new AtomicBoolean(true);
        public OrderEventConsumer(OrderEventProducer orderEventProducer, ThreadPoolManager threadPoolManager) {
            this.orderEventProducer = orderEventProducer;
            this.threadPoolManager = threadPoolManager;
        }
        @Override
        public void run(ApplicationArguments args) {
            for (int i = 0; i < CONSUMER_THREAD_NUM; i++) {
                Thread consumerThread = new Thread(this::doConsume, "order-event-consumer-" + i);
                consumerThread.setDaemon(false);
                consumerThread.start();
            }
            log.info("订单事件消费者启动完成,消费线程数:{}", CONSUMER_THREAD_NUM);
        }
        /**
         * 核心消费逻辑
         */
        private void doConsume() {
            while (isRunning.get() || orderEventProducer.getQueueSize() > 0) {
                try {
                    OrderEvent event = orderEventProducer.pollEvent(POLL_TIMEOUT, TimeUnit.SECONDS);
                    if (org.springframework.util.ObjectUtils.isEmpty(event)) {
                        continue;
                    }
                    dispatchEvent(event);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.error("消费线程被中断,线程名:{}", Thread.currentThread().getName(), e);
                    break;
                } catch (Exception e) {
                    log.error("消费事件发生未知异常", e);
                }
            }
            log.info("消费线程退出,线程名:{}", Thread.currentThread().getName());
        }
        /**
         * 事件分发到对应业务线程池
         * @param event 订单事件
         */
        private void dispatchEvent(OrderEvent event) {
            switch (event.getEventType()) {
                case "SMS_NOTIFY" -> threadPoolManager.getSmsNotifyExecutor().execute(() -> handleSmsNotify(event));
                case "LOGISTICS_SYNC" -> threadPoolManager.getLogisticsSyncExecutor().execute(() -> handleLogisticsSync(event));
                case "POINT_GRANT" -> threadPoolManager.getPointGrantExecutor().execute(() -> handlePointGrant(event));
                case "USER_PROFILE_UPDATE" -> threadPoolManager.getUserProfileExecutor().execute(() -> handleUserProfileUpdate(event));
                default -> log.warn("未知事件类型,event:{}", event);
            }
        }
        private void handleSmsNotify(OrderEvent event) {
            log.info("处理短信通知事件,orderNo:{}", event.getOrderNo());
        }
        private void handleLogisticsSync(OrderEvent event) {
            log.info("处理物流同步事件,orderNo:{}", event.getOrderNo());
        }
        private void handlePointGrant(OrderEvent event) {
            log.info("处理积分赠送事件,orderNo:{}", event.getOrderNo());
        }
        private void handleUserProfileUpdate(OrderEvent event) {
            log.info("处理用户画像更新事件,orderNo:{}", event.getOrderNo());
        }
        @Override
        public void destroy() {
            isRunning.set(false);
            log.info("消费者开始优雅停机,剩余待处理事件数:{}", orderEventProducer.getQueueSize());
        }
    }

    二、线程池隔离:高并发系统的舱壁模式落地

    2.1 为什么必须做线程池隔离?

    绝大多数高并发雪崩故障,都源于共用资源池的级联故障。在传统单线程池架构中,所有业务任务共用同一个线程池,一旦某一个慢任务(如第三方接口超时、慢SQL)占满了线程池,会导致所有业务任务都无法执行,最终整个服务不可用。

    举个典型的电商场景:订单服务包含四个核心操作,下单扣库存、发送短信、同步物流、更新用户画像。如果物流第三方接口超时,导致线程池内的所有线程都阻塞在该接口调用上,那么核心的下单扣库存任务也无法获取线程执行,整个订单服务瘫痪,这就是典型的线程池雪崩。

    线程池隔离的核心思想来自舱壁模式(Bulkhead Pattern),源于船舶设计:船舶的船舱被隔离为多个独立舱室,单个舱室进水不会导致整个船舶沉没。对应到系统中,就是将不同类型的业务任务,拆分到独立的线程池中执行,单个线程池因故障占满,不会影响其他线程池的任务执行,实现故障隔离,避免级联雪崩。

    2.2 线程池核心原理与执行流程

    线程池隔离的前提,是彻底理解线程池的核心参数与执行逻辑,否则隔离只会流于形式,无法真正实现故障隔离。

    2.2.1 线程池核心参数
    复制代码
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
    1. corePoolSize:核心线程数,线程池常驻的线程数量,默认不会被回收

    2. maximumPoolSize:最大线程数,线程池能容纳的最大线程数量

    3. keepAliveTime:非核心线程的空闲存活时间,超过该时间未执行任务的非核心线程会被回收

    4. unit:存活时间的单位

    5. workQueue:工作队列,存放等待执行的任务

    6. threadFactory:线程工厂,用于创建线程,生产环境必须自定义,设置线程名称与异常处理器,方便问题排查

    7. handler:拒绝策略,当线程池与工作队列都满时,处理新任务的策略

    2.2.2 线程池执行流程
    2.2.3 拒绝策略选型指南

    JDK提供了4种默认拒绝策略,生产环境需按业务场景严格选型:

    1. AbortPolicy:默认策略,直接抛出RejectedExecutionException异常,适合核心业务,及时感知故障

    2. CallerRunsPolicy:由调用线程执行任务,实现自动降级,避免任务丢失,适合核心写业务

    3. DiscardPolicy:直接丢弃任务,不抛出异常,适合非核心、可丢失的业务

    4. DiscardOldestPolicy:丢弃队列中最旧的任务,重试提交当前任务,适合优先级均匀的场景

    2.3 生产级线程池隔离完整实现

    2.3.1 自定义线程工厂
    复制代码
    package com.jam.demo.factory;
    import lombok.extern.slf4j.Slf4j;
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.atomic.AtomicInteger;
    @Slf4j
    public class CustomThreadFactory implements ThreadFactory {
        private final String threadNamePrefix;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final boolean isDaemon;
        public CustomThreadFactory(String threadNamePrefix, boolean isDaemon) {
            this.threadNamePrefix = threadNamePrefix;
            this.isDaemon = isDaemon;
        }
        @Override
        public Thread newThread(Runnable r) {
            String threadName = threadNamePrefix + "-" + threadNumber.getAndIncrement();
            Thread thread = new Thread(r, threadName);
            thread.setDaemon(isDaemon);
            thread.setUncaughtExceptionHandler((t, e) -> log.error("线程{}发生未捕获异常", t.getName(), e));
            return thread;
        }
    }
    2.3.2 自定义拒绝策略
    复制代码
    package com.jam.demo.handler;
    import lombok.extern.slf4j.Slf4j;
    import java.util.concurrent.RejectedExecutionHandler;
    import java.util.concurrent.ThreadPoolExecutor;
    @Slf4j
    public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
        private final String threadPoolName;
        public CustomRejectedExecutionHandler(String threadPoolName) {
            this.threadPoolName = threadPoolName;
        }
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            log.error("线程池[{}]触发拒绝策略,核心线程数:{},最大线程数:{},活跃线程数:{},队列积压数:{}",
                    threadPoolName,
                    executor.getCorePoolSize(),
                    executor.getMaximumPoolSize(),
                    executor.getActiveCount(),
                    executor.getQueue().size());
            if (!executor.isShutdown()) {
                r.run();
            }
        }
    }
    2.3.3 线程池管理器
    复制代码
    package com.jam.demo.manager;
    import com.jam.demo.factory.CustomThreadFactory;
    import com.jam.demo.handler.CustomRejectedExecutionHandler;
    import lombok.Getter;
    import org.springframework.stereotype.Component;
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    @Getter
    @Component
    public class ThreadPoolManager {
        private static final int CPU_CORE_NUM = Runtime.getRuntime().availableProcessors();
        private final ThreadPoolExecutor orderCoreExecutor;
        private final ThreadPoolExecutor smsNotifyExecutor;
        private final ThreadPoolExecutor logisticsSyncExecutor;
        private final ThreadPoolExecutor pointGrantExecutor;
        private final ThreadPoolExecutor userProfileExecutor;
        public ThreadPoolManager() {
            this.orderCoreExecutor = new ThreadPoolExecutor(
                    CPU_CORE_NUM,
                    CPU_CORE_NUM * 2,
                    60L,
                    TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(1000),
                    new CustomThreadFactory("order-core-pool", false),
                    new CustomRejectedExecutionHandler("order-core-pool")
            );
            this.smsNotifyExecutor = new ThreadPoolExecutor(
                    CPU_CORE_NUM * 10,
                    CPU_CORE_NUM * 20,
                    60L,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(5000),
                    new CustomThreadFactory("sms-notify-pool", false),
                    new CustomRejectedExecutionHandler("sms-notify-pool")
            );
            this.logisticsSyncExecutor = new ThreadPoolExecutor(
                    CPU_CORE_NUM * 5,
                    CPU_CORE_NUM * 10,
                    60L,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(2000),
                    new CustomThreadFactory("logistics-sync-pool", false),
                    new CustomRejectedExecutionHandler("logistics-sync-pool")
            );
            this.pointGrantExecutor = new ThreadPoolExecutor(
                    CPU_CORE_NUM * 8,
                    CPU_CORE_NUM * 15,
                    60L,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(3000),
                    new CustomThreadFactory("point-grant-pool", false),
                    new CustomRejectedExecutionHandler("point-grant-pool")
            );
            this.userProfileExecutor = new ThreadPoolExecutor(
                    CPU_CORE_NUM * 2,
                    CPU_CORE_NUM * 4,
                    60L,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(1000),
                    new CustomThreadFactory("user-profile-pool", false),
                    new CustomRejectedExecutionHandler("user-profile-pool")
            );
        }
    }
    2.3.4 线程池监控实现
    复制代码
    package com.jam.demo.monitor;
    import com.jam.demo.manager.ThreadPoolManager;
    import com.jam.demo.producer.OrderEventProducer;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    import java.util.concurrent.ThreadPoolExecutor;
    @Slf4j
    @Component
    public class ThreadPoolMonitor {
        private final ThreadPoolManager threadPoolManager;
        private final OrderEventProducer orderEventProducer;
        public ThreadPoolMonitor(ThreadPoolManager threadPoolManager, OrderEventProducer orderEventProducer) {
            this.threadPoolManager = threadPoolManager;
            this.orderEventProducer = orderEventProducer;
        }
        @Scheduled(fixedRate = 60000)
        public void printThreadPoolMetrics() {
            log.info("====================线程池监控指标====================");
            printExecutorMetrics("order-core-pool", threadPoolManager.getOrderCoreExecutor());
            printExecutorMetrics("sms-notify-pool", threadPoolManager.getSmsNotifyExecutor());
            printExecutorMetrics("logistics-sync-pool", threadPoolManager.getLogisticsSyncExecutor());
            printExecutorMetrics("point-grant-pool", threadPoolManager.getPointGrantExecutor());
            printExecutorMetrics("user-profile-pool", threadPoolManager.getUserProfileExecutor());
            log.info("事件队列积压数:{},剩余容量:{}", orderEventProducer.getQueueSize(), orderEventProducer.getRemainingCapacity());
            log.info("======================================================");
        }
        private void printExecutorMetrics(String poolName, ThreadPoolExecutor executor) {
            log.info("[{}] 核心线程数:{},最大线程数:{},活跃线程数:{},完成任务数:{},队列积压数:{},拒绝任务数:{}",
                    poolName,
                    executor.getCorePoolSize(),
                    executor.getMaximumPoolSize(),
                    executor.getActiveCount(),
                    executor.getCompletedTaskCount(),
                    executor.getQueue().size(),
                    executor.getRejectedExecutionHandler().getClass().getSimpleName());
        }
    }

    三、完整业务落地:订单系统的高并发实现

    3.1 业务架构设计

    3.2 数据库表设计(MySQL 8.0)

    复制代码
    CREATE TABLE `t_order` (
      `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `order_no` varchar(64) NOT NULL COMMENT '订单号',
      `user_id` bigint NOT NULL COMMENT '用户ID',
      `sku_id` bigint NOT NULL COMMENT '商品SKU ID',
      `buy_num` int NOT NULL COMMENT '购买数量',
      `order_amount` decimal(12,2) NOT NULL COMMENT '订单金额',
      `order_status` tinyint NOT NULL DEFAULT '0' COMMENT '订单状态 0-待支付 1-已支付 2-已发货 3-已完成 4-已取消',
      `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
      PRIMARY KEY (`id`),
      UNIQUE KEY `uk_order_no` (`order_no`),
      KEY `idx_user_id` (`user_id`),
      KEY `idx_create_time` (`create_time`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单表';
    
    CREATE TABLE `t_sku_stock` (
      `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `sku_id` bigint NOT NULL COMMENT '商品SKU ID',
      `stock_num` int NOT NULL DEFAULT '0' COMMENT '库存数量',
      `lock_stock_num` int NOT NULL DEFAULT '0' COMMENT '锁定库存数量',
      `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
      PRIMARY KEY (`id`),
      UNIQUE KEY `uk_sku_id` (`sku_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品库存表';

    3.3 实体类定义

    复制代码
    package com.jam.demo.entity;
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import io.swagger.v3.oas.annotations.media.Schema;
    import lombok.Data;
    import java.io.Serial;
    import java.io.Serializable;
    import java.math.BigDecimal;
    import java.time.LocalDateTime;
    @Data
    @TableName("t_order")
    @Schema(description = "订单实体")
    public class Order implements Serializable {
        @Serial
        private static final long serialVersionUID = 1L;
        @TableId(type = IdType.AUTO)
        @Schema(description = "主键ID")
        private Long id;
        @Schema(description = "订单号")
        private String orderNo;
        @Schema(description = "用户ID")
        private Long userId;
        @Schema(description = "商品SKU ID")
        private Long skuId;
        @Schema(description = "购买数量")
        private Integer buyNum;
        @Schema(description = "订单金额")
        private BigDecimal orderAmount;
        @Schema(description = "订单状态")
        private Integer orderStatus;
        @Schema(description = "创建时间")
        private LocalDateTime createTime;
        @Schema(description = "更新时间")
        private LocalDateTime updateTime;
    }
    
    package com.jam.demo.entity;
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import io.swagger.v3.oas.annotations.media.Schema;
    import lombok.Data;
    import java.io.Serial;
    import java.io.Serializable;
    import java.time.LocalDateTime;
    @Data
    @TableName("t_sku_stock")
    @Schema(description = "库存实体")
    public class SkuStock implements Serializable {
        @Serial
        private static final long serialVersionUID = 1L;
        @TableId(type = IdType.AUTO)
        @Schema(description = "主键ID")
        private Long id;
        @Schema(description = "商品SKU ID")
        private Long skuId;
        @Schema(description = "库存数量")
        private Integer stockNum;
        @Schema(description = "锁定库存数量")
        private Integer lockStockNum;
        @Schema(description = "创建时间")
        private LocalDateTime createTime;
        @Schema(description = "更新时间")
        private LocalDateTime updateTime;
    }

    3.4 Mapper接口定义

    复制代码
    package com.jam.demo.mapper;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.jam.demo.entity.Order;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Update;
    public interface OrderMapper extends BaseMapper<Order> {
    }
    
    package com.jam.demo.mapper;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.jam.demo.entity.SkuStock;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Update;
    public interface SkuStockMapper extends BaseMapper<SkuStock> {
        @Update("UPDATE t_sku_stock SET stock_num = stock_num - #{buyNum}, lock_stock_num = lock_stock_num + #{buyNum} WHERE sku_id = #{skuId} AND stock_num >= #{buyNum}")
        int deductStock(@Param("skuId") Long skuId, @Param("buyNum") Integer buyNum);
    }

    3.5 核心订单服务实现

    复制代码
    package com.jam.demo.service;
    import com.jam.demo.entity.Order;
    import com.jam.demo.manager.ThreadPoolManager;
    import com.jam.demo.mapper.OrderMapper;
    import com.jam.demo.mapper.SkuStockMapper;
    import com.jam.demo.model.OrderEvent;
    import com.jam.demo.producer.OrderEventProducer;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.support.TransactionTemplate;
    import java.time.LocalDateTime;
    import java.util.UUID;
    @Slf4j
    @Service
    public class OrderService {
        private final OrderMapper orderMapper;
        private final SkuStockMapper skuStockMapper;
        private final TransactionTemplate transactionTemplate;
        private final OrderEventProducer orderEventProducer;
        private final ThreadPoolManager threadPoolManager;
        public OrderService(OrderMapper orderMapper, SkuStockMapper skuStockMapper, TransactionTemplate transactionTemplate, OrderEventProducer orderEventProducer, ThreadPoolManager threadPoolManager) {
            this.orderMapper = orderMapper;
            this.skuStockMapper = skuStockMapper;
            this.transactionTemplate = transactionTemplate;
            this.orderEventProducer = orderEventProducer;
            this.threadPoolManager = threadPoolManager;
        }
        /**
         * 创建订单
         * @param userId 用户ID
         * @param skuId 商品SKU ID
         * @param buyNum 购买数量
         * @return 订单号
         */
        public String createOrder(Long userId, Long skuId, Integer buyNum) {
            if (org.springframework.util.ObjectUtils.isEmpty(userId) || org.springframework.util.ObjectUtils.isEmpty(skuId) || org.springframework.util.ObjectUtils.isEmpty(buyNum) || buyNum <= 0) {
                throw new IllegalArgumentException("订单参数异常");
            }
            String orderNo = UUID.randomUUID().toString().replace("-", "");
            Boolean result = transactionTemplate.execute(status -> {
                try {
                    int deductResult = skuStockMapper.deductStock(skuId, buyNum);
                    if (deductResult <= 0) {
                        log.warn("库存扣减失败,skuId:{}, buyNum:{}", skuId, buyNum);
                        status.setRollbackOnly();
                        return false;
                    }
                    Order order = new Order();
                    order.setOrderNo(orderNo);
                    order.setUserId(userId);
                    order.setSkuId(skuId);
                    order.setBuyNum(buyNum);
                    order.setOrderAmount(java.math.BigDecimal.valueOf(100).multiply(java.math.BigDecimal.valueOf(buyNum)));
                    order.setOrderStatus(0);
                    order.setCreateTime(LocalDateTime.now());
                    order.setUpdateTime(LocalDateTime.now());
                    orderMapper.insert(order);
                    log.info("订单创建成功,orderNo:{}", orderNo);
                    return true;
                } catch (Exception e) {
                    log.error("订单创建异常,orderNo:{}", orderNo, e);
                    status.setRollbackOnly();
                    return false;
                }
            });
            if (Boolean.TRUE.equals(result)) {
                publishOrderEvent(orderNo, userId);
                return orderNo;
            } else {
                throw new RuntimeException("订单创建失败");
            }
        }
        /**
         * 发布订单完成事件
         * @param orderNo 订单号
         * @param userId 用户ID
         */
        private void publishOrderEvent(String orderNo, Long userId) {
            String[] eventTypes = {"SMS_NOTIFY", "LOGISTICS_SYNC", "POINT_GRANT", "USER_PROFILE_UPDATE"};
            for (String eventType : eventTypes) {
                OrderEvent event = OrderEvent.builder()
                        .eventId(UUID.randomUUID().toString().replace("-", ""))
                        .orderNo(orderNo)
                        .userId(userId)
                        .eventType(eventType)
                        .retryTimes(0)
                        .maxRetryTimes(3)
                        .createTime(LocalDateTime.now())
                        .build();
                orderEventProducer.sendEvent(event);
            }
        }
    }

    3.6 订单控制器实现

    复制代码
    package com.jam.demo.controller;
    import com.jam.demo.service.OrderService;
    import io.swagger.v3.oas.annotations.Operation;
    import io.swagger.v3.oas.annotations.Parameter;
    import io.swagger.v3.oas.annotations.tags.Tag;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    @RestController
    @RequestMapping("/api/order")
    @Tag(name = "订单管理", description = "订单核心操作接口")
    public class OrderController {
        private final OrderService orderService;
        public OrderController(OrderService orderService) {
            this.orderService = orderService;
        }
        @PostMapping("/create")
        @Operation(summary = "创建订单", description = "用户下单创建订单接口")
        public ResponseEntity<String> createOrder(
                @Parameter(description = "用户ID", required = true) @RequestParam Long userId,
                @Parameter(description = "商品SKU ID", required = true) @RequestParam Long skuId,
                @Parameter(description = "购买数量", required = true) @RequestParam Integer buyNum) {
            String orderNo = orderService.createOrder(userId, skuId, buyNum);
            return ResponseEntity.ok(orderNo);
        }
    }

    3.7 配置文件(application.yml)

    复制代码
    server:
      port: 8080
      shutdown: graceful
    spring:
      application:
        name: high-concurrency-demo
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/demo_order?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
        username: root
        password: root
        driver-class-name: com.mysql.cj.jdbc.Driver
      lifecycle:
        timeout-per-shutdown-phase: 30s
    springdoc:
      swagger-ui:
        path: /swagger-ui.html
        enabled: true
      api-docs:
        enabled: true
        path: /v3/api-docs
    mybatis-plus:
      mapper-locations: classpath*:/mapper/**/*.xml
      configuration:
        map-underscore-to-camel-case: true
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    四、高并发落地避坑指南

    4.1 阻塞队列使用的核心坑点

    • 无界队列导致OOM:LinkedBlockingQueue默认容量为Integer.MAX_VALUE,生产速度超过消费速度时,队列会无限膨胀,最终触发OOM。生产环境必须为所有阻塞队列强制指定容量。

    • 队列容量设置不合理 :容量过小会频繁触发拒绝策略,容量过大会导致任务积压、接口RT升高,甚至触发Full GC。队列容量需根据压测结果设置,公式参考:队列容量 = 核心线程数 * 单任务平均执行时间 * 峰值QPS

    4.2 线程池使用的核心坑点

    • 共用线程池导致雪崩:核心业务与非核心业务共用线程池,非核心业务的慢任务会占满线程池,导致核心业务无法执行。必须按业务场景与任务类型做线程池隔离。

    • 线程数设置不合理 :CPU密集型任务设置过多线程,会导致频繁的上下文切换,CPU利用率拉满但吞吐量骤降;IO密集型任务设置过少线程,会导致CPU资源浪费。CPU密集型任务核心线程数建议设置为CPU核心数+1,IO密集型任务建议设置为CPU核心数 * 阻塞系数/(1-阻塞系数),阻塞系数通常为0.8-0.9。

    • 使用Executors创建线程池:Executors创建的线程池均存在风险,FixedThreadPool和SingleThreadPool使用无界队列,CachedThreadPool使用无界最大线程数,都会导致OOM。生产环境必须使用ThreadPoolExecutor手动创建线程池。

    4.3 生产者-消费者模式的核心坑点

    • 虚假唤醒导致逻辑异常:使用if判断wait()的条件,而非while循环,线程被虚假唤醒后,条件不满足仍会继续执行,导致数据异常。JDK官方强制要求wait()必须放在while循环中,每次唤醒后重新判断条件。

    • 消费线程异常退出:消费者业务逻辑未捕获异常,抛出RuntimeException后,消费线程会直接终止,无法继续消费,导致任务无限积压。消费者的业务逻辑必须用try-catch捕获所有异常,记录日志并做重试/降级处理,保证消费线程不会退出。

    • 优雅停机导致任务丢失:服务直接使用kill -9终止,消费者线程立即停止,队列中未处理的任务会直接丢失。必须实现优雅停机,服务停止时先关闭生产者,再等待消费者处理完队列中的存量任务,最后关闭线程池,使用kill -15终止服务。

    4.4 线程池隔离的核心坑点

    • 隔离粒度过细/过粗:隔离粒度过细会导致线程数过多,上下文切换频繁;隔离粒度过粗会导致隔离失效。建议按业务域+任务类型做隔离,核心业务单独隔离,非核心业务可合并隔离。

    • 拒绝策略使用不当:核心业务使用DiscardPolicy会导致任务丢失,非核心业务使用AbortPolicy会影响用户体验。核心写业务建议使用CallerRunsPolicy实现降级,非核心业务可使用DiscardPolicy,同时记录告警日志。


    五、总结

    生产者-消费者范式与线程池隔离,是高并发系统的两大核心支柱。生产者-消费者通过异步解耦,实现了系统的削峰填谷与吞吐量提升;线程池隔离通过舱壁模式,实现了系统的故障隔离与稳定性保障。二者结合,才能构建出既能扛住高并发流量冲击,又能保证业务连续性的生产级系统。 本文从底层JDK线程通信机制,到完整的电商订单业务落地,完整拆解了两大范式的实现逻辑与生产级规范。高并发编程的核心,从来不是炫技式的API调用,而是对底层原理的深刻理解,以及对生产环境风险的提前预判,只有把基础打牢,才能写出真正稳定、高性能的高并发代码。