基础讲解
固定式线程池 + 任务队列 核心概念讲解
简单来说:
固定式线程池:提前创建固定数量的工作线程,线程一旦创建不会动态增减(区别于可扩容的缓存线程池),避免频繁创建 / 销毁线程的性能开销。
任务队列:作为 "缓冲池",存放暂时来不及处理的任务,让线程池中的工作线程从队列中逐个取任务执行,避免请求直接被拒绝或线程数爆炸。
这一组合是 RPC 框架处理网络请求、异步回调、序列化 / 反序列化等任务的核心基础。
一、核心设计思想:"池化" + "缓冲"
在分布式系统(如 RPC)中,每收到一个远程调用请求就创建一个新线程处理,会带来两个致命问题:
- 线程创建 / 销毁的性能开销极大(涉及内核态 / 用户态切换、栈内存分配);
- 线程数无限制增长会耗尽系统内存,导致 OOM(内存溢出)或 CPU 上下文切换频繁,系统性能雪崩。
而 "固定式线程池 + 任务队列" 通过两个核心手段解决:
- 池化(线程池):提前创建 N 个线程并复用,线程运行期间不销毁,处理完一个任务就取下一个,直到线程池关闭;
- 缓冲(任务队列):所有待处理的任务先进入队列排队,工作线程从队列中 "消费" 任务,避免请求直接被丢弃,也避免线程数失控。
二、核心组成与工作流程
1. 核心组成部分
| 组件 | 作用 | 关键特性 |
|---|---|---|
| 任务队列(Task Queue) | 存储待执行的任务(如 RPC 请求处理逻辑) | 通常是阻塞队列(BlockingQueue),队列为空时线程阻塞等待,队列满时可拒绝 / 阻塞提交者 |
| 工作线程池(Fixed Thread Pool) | 固定数量的工作线程 | 线程数 corePoolSize = maximumPoolSize(无扩容),线程空闲时不会销毁,持续监听队列 |
| 任务提交接口 | 向线程池提交任务的入口 | 支持提交 Runnable/Callable 任务,返回 Future(异步结果) |
| 拒绝策略 | 任务队列满时的处理逻辑 | 如抛异常、丢弃任务、调用者自行执行、丢弃最老任务 |
2. 完整工作流程(以 RPC 请求处理为例)

具体步骤拆解:
- 任务提交:RPC 服务端接收到客户端的调用请求后,将 "处理这个请求" 的逻辑封装成一个任务对象,提交到线程池的任务队列;
- 线程监听:线程池中固定数量的工作线程会持续监听任务队列;
- 任务消费 :如果队列中有任务,空闲线程会取出任务并执行(执行过程包括反序列化参数、调用本地函数、序列化结果等);如果队列为空,线程会进入阻塞状态(不会占用 CPU 资源),直到队列中有新任务;
- 队列满处理 :如果任务提交速度远大于线程处理速度,任务队列会被填满,此时线程池会触发拒绝策略(比如抛异常,或让提交任务的线程自己执行);
- 线程复用:工作线程处理完一个任务后,不会销毁,而是回到 "监听队列" 的状态,等待下一个任务。
总结
关键点回顾
- 核心价值:固定式线程池 + 任务队列通过 "线程复用" 和 "任务缓冲",解决了 RPC 系统中线程频繁创建销毁、并发数失控的问题,提升稳定性和性能;
- 核心逻辑:任务先入队列,固定数量的工作线程从队列取任务执行,队列为空时线程阻塞,队列满时触发拒绝策略;
- 关键配置:线程数需根据任务类型(CPU/IO 密集型)调整,任务队列需设置长度限制,避免内存溢出。
代码实现
任务队列
cpp
#ifndef SYNCQUEUE_HPP
#define SYNCQUEUE_HPP
#include<condition_variable>
#include<mutex>
#include<queue>
#include<list>
#include<iostream>
using namespace std;
const int MaxTaskCount=200;
template<typename T>
class SyncQueue {
// Class definition goes here
private:
std::list<T> queue;
mutable std::mutex mtx;
std::condition_variable notEmpty;
std::condition_variable notFull;
int maxTaskCount;
bool stop;
bool IsFull() const {
bool full=queue.size() > maxTaskCount;
if(full){
std::cout<<"SyncQueue is full!"<<std::endl;
return true;
}
return false;
}
bool IsEmpty() const {
bool empty=queue.empty();
if(empty){
std::cout<<"SyncQueue is empty!"<<std::endl;
return true;
}
return false;
}
template<typename F>
void Add(F&& task){
std::unique_lock<std::mutex> lock(mtx);
notFull.wait(lock,[this](){return !IsFull() || stop;});
if(stop) return;
queue.push_back(std::forward<F>(task));
notEmpty.notify_one();
}
// Member variables and methods
public:
SyncQueue(int maxSize=MaxTaskCount):maxTaskCount(maxSize),stop(false){}
~SyncQueue(){
Stop();
}
void Put(const T& task){
Add(task);
}
void Put(T&& task){
Add(std::forward<T>(task));
}
// void Take(std::list<T>& tasks){
// std::unique_lock<std::mutex> lock(mtx);
// notEmpty.wait(lock,[this](){return !IsEmpty() || stop;});
// if(stop) return;
// queue=std::move(tasks);
// notFull.notify_all();
// }
void Take(T& task){
std::unique_lock<std::mutex> lock(mtx);
notEmpty.wait(lock,[this](){return !IsEmpty() || stop;});
if(stop) return;
task=std::move(queue.front());
queue.pop_front();
notFull.notify_one();
}
void Stop(){
{
std::lock_guard<std::mutex> lock(mtx);
stop=true;
}
notEmpty.notify_all();
notFull.notify_all();
}
bool Empty() const{
std::lock_guard<std::mutex> lock(mtx);
return queue.empty();
}
bool Full() const{
std::lock_guard<std::mutex> lock(mtx);
return queue.size() >= maxTaskCount;
}
int Size() const{
std::lock_guard<std::mutex> lock(mtx);
return queue.size();
}
int Count() const{
std::lock_guard<std::mutex> lock(mtx);
return queue.size();
}
// Public interface
};
#endif
线程池代码
cpp
#ifndef FIEXDTHREADPOOL_HPP
#define FIEXDTHREADPOOL_HPP
#include"SyncQueue.hpp"
#include<functional>
#include<list>
#include<thread>
#include<vector>
#include<atomic>
class FixedThreadPool {
// Class definition goes here
public:
using task=std::function<void()>;
private:
//std::list<std::shared_ptr<std::thread>> tasks;
std::vector<std::thread> threadgroup;
SyncQueue<task> taskqueue;
std::atomic_bool isrunning;
std::once_flag flag;
void Start(int threadNum){
isrunning=true;
for(int i=0;i<threadNum;++i){
threadgroup.emplace_back([this](){this->Run();});
}
}
void Run(){
while(isrunning){
task t;
taskqueue.Take(t);
if(!isrunning) break;
if(t){
t();
}
}
}
void stop(){
taskqueue.Stop();
for(auto& th:threadgroup){
if(th.joinable()){
th.join();
}
}
threadgroup.clear();
}
public:
FixedThreadPool(int threadNum=4,int maxTaskCount=200):taskqueue(maxTaskCount),isrunning(false){
Start(threadNum);
}
~FixedThreadPool(){
Stop();
}
void Stop(){
std::call_once(flag,[this]{stop();});
}
void AddTask(const task& t){
taskqueue.Put(t);
}
void AddTask(task&& t){
taskqueue.Put(std::forward<task>(t));
}
};
#endif