线程池
为什么要使用线程池
线程池能复用线程,提升性能,减少资源消耗。
统一管理线程数量,防止线程无限增长导致系统崩溃。
支持任务排队、限流、超时、拒绝策略等高级功能。
方便监控和调优。
线程池配置类
需要使用的注解
@Configuration,让Spring识别该类为配置类,自动加载并注册@Bean方法。@EnableAsync,开启Spring的异步方法支持,配合@Async注解,可以让方法异步执行(即在新线程中运行),常用于多线程任务、异步调用等场景。
需要配置的参数
corePoolSize:线程池核心线程数量,线程池中长期保留的线程数量,即使空闲也不回收,建议直接等于运行电脑的逻辑处理器数量N。逻辑处理器数N代表的含义:同一时刻,最多有N个线程正在CPU上执行指令。maximumPoolSize:线程池最大线程数量,因为IO密集型线程大量时间在“等”,不在“算”,所以可以大于电脑的逻辑处理器数量N,建议设置为2N~4N。多开一些线程,同一时刻总有一部分在等IO、一部分在跑CPU这样CPU更容易被“喂饱”,利用率更高。keepAliverTime:当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间。无论是否大于逻辑处理器的线程都会放在内存里,只有当线程在运行过程中且需要计算的时候才会被CPU调度执行一段时间抢占时间片。当把最大存活时间设置地过大会出现资源占用时间长的问题,设置地太短会出现频繁创建/销毁,开销大的问题。大多数情况将最大存活时间设置为适中的30-180秒;不过根据具体情况而定也可以小于30秒或者大于180秒。unit:存活时间的单位。存活时间单位直接影响的是keepAliverTime的时间单位是秒还是分。建议为秒TimeUnit.SECONDS ,也可以为分TimeUnit.MINUTES 。workQueue:存放任务的队列。调整该参数前需要你决定线程池的策略是 “堆积等待” 还是 “快速扩容/快速失败”,不同队列类型会直接改变线程池的行为。ArrayBlockingQueue ,有界队列,推荐用于可控系统;LinkedBlockingQueue ,无界队列,如果不指定容量几乎是“无界”,任务会一直堆积容易OOM;SynchronousQueue ,不存储任务,直接交接。rejectedExecutionHandler:超出线程范围和队列容量的任务的处理程序。当遇到当前线程数 == maximumPoolSize且workQueue也满了(或SynchronousQueue交接失败),此时新任务进不去,就交给 handler 处理。CallerRunsPolicy(推荐:练习/压测/不想丢任务),让“提交任务的线程”自己执行该任务。AbortPolicy(推荐:需要明确失败、快速暴露问题),直接抛 RejectedExecutionException。DiscardPolicy / DiscardOldestPolicy(一般不推荐),悄悄丢任务,不报错(非常危险,容易“数据丢了还不知道”)。
线程池任务提交与执行全流程图
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 调用方提交 │ │ 前置限流 │ │ 进入线程池 │ │ 决策逻辑 │
│ 任务 │──▶│ (可选) │──▶│ execute() │──▶│ (顺序) │
│submit() │ │ QPS/令牌桶 │ │ │ │ │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 线程池内部决策流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ (1) 当前线程数 < corePoolSize? │
│ ┌───是───┐ 创建"核心线程"执行 │
│ └───否───┘ │
│ │ │
│ ▼ │
│ (2) 队列有空间? │
│ ┌───是───┐ 任务入队等待 │
│ └───否───┘ │
│ │ │
│ ▼ │
│ (3) 当前线程数 < maximumPoolSize? │
│ ┌───是───┐ 创建"非核心线程"执行 │
│ └───否───┘ │
│ │ │
│ ▼ │
│ (4) 触发拒绝策略: │
│ ┌──────────────────────────────┐ │
│ │ AbortPolicy: 抛异常 │ │
│ │ DiscardPolicy: 丢弃任务 │ │
│ │ DiscardOldestPolicy: 弃旧纳新│ │
│ │ CallerRunsPolicy: 调用者执行 │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘线程调度算法
优先调度算法
先来先服务调度算法
高优先权优先调度算法
非抢占式优先权算法
抢占式优先权调度算法
高响应比优先调度算法
基于时间片的轮转调度算法
时间片轮转法
多级反馈队列调度算法
消息队列做缓冲(外部排队,不丢任务)
Erlang+RabbitMQ
RabbitMQ 的服务端(Broker)是用 Erlang/OTP 写的,所以安装 RabbitMQ 之前必须先安装 Erlang。